src/core/names.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 04 Jul 2009 08:15:48 +0200
changeset 4654 2eaebe77d66b
parent 4298 cc2db3e6bcae
permissions -rw-r--r--
Added tag ns-3.5 for changeset c975274c9707
craigdo@4139
     1
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
craigdo@4139
     2
/*
craigdo@4139
     3
 * Copyright (c) 2009 University of Washington
craigdo@4139
     4
 *
craigdo@4139
     5
 * This program is free software; you can redistribute it and/or modify
craigdo@4139
     6
 * it under the terms of the GNU General Public License version 2 as
craigdo@4139
     7
 * published by the Free Software Foundation;
craigdo@4139
     8
 *
craigdo@4139
     9
 * This program is distributed in the hope that it will be useful,
craigdo@4139
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
craigdo@4139
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
craigdo@4139
    12
 * GNU General Public License for more details.
craigdo@4139
    13
 *
craigdo@4139
    14
 * You should have received a copy of the GNU General Public License
craigdo@4139
    15
 * along with this program; if not, write to the Free Software
craigdo@4139
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
craigdo@4139
    17
 */
craigdo@4139
    18
craigdo@4139
    19
#include <map>
craigdo@4145
    20
#include "object.h"
craigdo@4145
    21
#include "log.h"
craigdo@4145
    22
#include "assert.h"
craigdo@4145
    23
#include "abort.h"
craigdo@4147
    24
#include "names.h"
craigdo@4139
    25
#include "ns3/simulator.h"
craigdo@4139
    26
craigdo@4139
    27
namespace ns3 {
craigdo@4139
    28
craigdo@4139
    29
NS_LOG_COMPONENT_DEFINE ("Names");
craigdo@4139
    30
craigdo@4139
    31
class NameNode
craigdo@4139
    32
{
craigdo@4139
    33
public:
craigdo@4139
    34
  NameNode ();
craigdo@4139
    35
  NameNode (const NameNode &nameNode);
craigdo@4139
    36
  NameNode (NameNode *parent, std::string name, Ptr<Object> object);
craigdo@4139
    37
  NameNode &operator = (const NameNode &rhs);
craigdo@4139
    38
craigdo@4139
    39
 ~NameNode ();
craigdo@4139
    40
craigdo@4139
    41
  NameNode *m_parent;
craigdo@4139
    42
  std::string m_name;
craigdo@4139
    43
  Ptr<Object> m_object;
craigdo@4139
    44
craigdo@4139
    45
  std::map<std::string, NameNode *> m_nameMap;
craigdo@4139
    46
};
craigdo@4139
    47
craigdo@4139
    48
NameNode::NameNode ()
craigdo@4139
    49
  : m_parent (0), m_name (""), m_object (0)
craigdo@4139
    50
{
craigdo@4139
    51
}
craigdo@4139
    52
craigdo@4139
    53
NameNode::NameNode (const NameNode &nameNode)
craigdo@4139
    54
{
craigdo@4139
    55
  m_parent = nameNode.m_parent;
craigdo@4139
    56
  m_name = nameNode.m_name;
craigdo@4139
    57
  m_object = nameNode.m_object;
craigdo@4139
    58
  m_nameMap = nameNode.m_nameMap;
craigdo@4139
    59
}
craigdo@4139
    60
craigdo@4139
    61
NameNode &
craigdo@4139
    62
NameNode::operator = (const NameNode &rhs)
craigdo@4139
    63
{
craigdo@4139
    64
  m_parent = rhs.m_parent;
craigdo@4139
    65
  m_name = rhs.m_name;
craigdo@4139
    66
  m_object = rhs.m_object;
craigdo@4139
    67
  m_nameMap = rhs.m_nameMap;
craigdo@4139
    68
  return *this;
craigdo@4139
    69
}
craigdo@4139
    70
craigdo@4139
    71
NameNode::NameNode (NameNode *parent, std::string name, Ptr<Object> object)
craigdo@4139
    72
  : m_parent (parent), m_name (name), m_object (object)
craigdo@4139
    73
{
craigdo@4139
    74
}
craigdo@4139
    75
craigdo@4139
    76
NameNode::~NameNode ()
craigdo@4139
    77
{
craigdo@4139
    78
}
craigdo@4139
    79
craigdo@4139
    80
class NamesPriv 
craigdo@4139
    81
{
craigdo@4139
    82
public:
craigdo@4139
    83
  NamesPriv ();
craigdo@4139
    84
  ~NamesPriv ();
craigdo@4139
    85
tomh@4481
    86
  bool Add (std::string name, Ptr<Object> object);
craigdo@4159
    87
  bool Add (std::string path, std::string name, Ptr<Object> object);
craigdo@4139
    88
  bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
craigdo@4159
    89
craigdo@4159
    90
  bool Rename (std::string oldpath, std::string newname);
craigdo@4159
    91
  bool Rename (std::string path, std::string oldname, std::string newname);
craigdo@4153
    92
  bool Rename (Ptr<Object> context, std::string oldname, std::string newname);
craigdo@4159
    93
craigdo@4158
    94
  std::string FindName (Ptr<Object> object);
craigdo@4158
    95
  std::string FindPath (Ptr<Object> object);
craigdo@4159
    96
craigdo@4158
    97
  Ptr<Object> Find (std::string name);
craigdo@4158
    98
  Ptr<Object> Find (std::string path, std::string name);
craigdo@4158
    99
  Ptr<Object> Find (Ptr<Object> context, std::string name);
craigdo@4139
   100
craigdo@4139
   101
  static NamesPriv *Get (void);
craigdo@4145
   102
  static void Delete (void);
craigdo@4139
   103
private:
craigdo@4161
   104
  static NamesPriv **DoGet (bool doCreate);
craigdo@4139
   105
craigdo@4139
   106
  NameNode *IsNamed (Ptr<Object>);
craigdo@4139
   107
  bool IsDuplicateName (NameNode *node, std::string name);
craigdo@4139
   108
craigdo@4139
   109
  NameNode m_root;
craigdo@4139
   110
  std::map<Ptr<Object>, NameNode *> m_objectMap;
craigdo@4139
   111
};
craigdo@4139
   112
craigdo@4139
   113
NamesPriv *
craigdo@4139
   114
NamesPriv::Get (void)
craigdo@4139
   115
{
craigdo@4161
   116
  return *(DoGet (true));
craigdo@4139
   117
}
craigdo@4139
   118
craigdo@4139
   119
NamesPriv **
craigdo@4161
   120
NamesPriv::DoGet (bool doCreate)
craigdo@4139
   121
{
craigdo@4139
   122
  static NamesPriv *ptr = 0;
craigdo@4139
   123
craigdo@4161
   124
  if (ptr == 0 && doCreate)
craigdo@4139
   125
    {
craigdo@4139
   126
      ptr = new NamesPriv;
craigdo@4139
   127
      Simulator::ScheduleDestroy (&NamesPriv::Delete);
craigdo@4139
   128
    }
craigdo@4139
   129
craigdo@4139
   130
  return &ptr;
craigdo@4139
   131
}
craigdo@4139
   132
craigdo@4139
   133
void 
craigdo@4139
   134
NamesPriv::Delete (void)
craigdo@4139
   135
{
craigdo@4139
   136
  NS_LOG_FUNCTION_NOARGS ();
craigdo@4139
   137
craigdo@4161
   138
  NamesPriv **ptr = DoGet (false);
craigdo@4139
   139
  delete *ptr;
craigdo@4139
   140
  *ptr = 0;
craigdo@4139
   141
}
craigdo@4139
   142
craigdo@4139
   143
NamesPriv::NamesPriv ()
craigdo@4139
   144
{
craigdo@4139
   145
  NS_LOG_FUNCTION_NOARGS ();
craigdo@4139
   146
craigdo@4139
   147
  m_root.m_parent = 0;
craigdo@4139
   148
  m_root.m_name = "Names";
craigdo@4139
   149
  m_root.m_object = 0;
craigdo@4139
   150
}
craigdo@4139
   151
craigdo@4139
   152
NamesPriv::~NamesPriv ()
craigdo@4139
   153
{
craigdo@4139
   154
  NS_LOG_FUNCTION_NOARGS ();
craigdo@4139
   155
craigdo@4139
   156
  //
craigdo@4139
   157
  // Every name is associated with an object in the object map, so freeing the
craigdo@4139
   158
  // NameNodes in this map will free all of the memory allocated for the NameNodes
craigdo@4139
   159
  //
craigdo@4139
   160
  for (std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.begin (); i != m_objectMap.end (); ++i)
craigdo@4139
   161
    {
craigdo@4139
   162
      delete i->second;
craigdo@4139
   163
      i->second = 0;
craigdo@4139
   164
    }
craigdo@4145
   165
craigdo@4145
   166
  m_root.m_parent = 0;
craigdo@4145
   167
  m_root.m_name = "";
craigdo@4145
   168
  m_root.m_object = 0;
craigdo@4139
   169
}
craigdo@4139
   170
craigdo@4139
   171
bool
craigdo@4139
   172
NamesPriv::Add (std::string name, Ptr<Object> object)
craigdo@4139
   173
{
craigdo@4141
   174
  NS_LOG_FUNCTION (name << object);
craigdo@4141
   175
  //
craigdo@4141
   176
  // This is the simple, easy to use version of Add, so we want it to be flexible.
craigdo@4151
   177
  // We don't want to force a user to always type the fully qualified namespace 
craigdo@4151
   178
  // name, so we allow the namespace name to be omitted.  For example, calling
craigdo@4151
   179
  // Add ("Client/ath0", obj) should result in exactly the same behavior as
craigdo@4151
   180
  // Add ("/Names/Client/ath0", obj).  Calling Add ("Client", obj) should have
craigdo@4151
   181
  // the same effect as Add ("Names/Client", obj)
craigdo@4141
   182
  //
craigdo@4151
   183
  // The first thing to do, then, is to "canonicalize" the input string to always
craigdo@4151
   184
  // be a fully qualified name.
craigdo@4141
   185
  //
craigdo@4141
   186
  // If we are given a name that begins with "/Names/" we assume that this is a
craigdo@4159
   187
  // fully qualified path name to the object we want to create.  We split the name
craigdo@4159
   188
  // into a path string and and a final segment (name) and then call the "Real" Add.
craigdo@4141
   189
  //
craigdo@4141
   190
  std::string namespaceName = "/Names";
craigdo@4141
   191
  std::string::size_type offset = name.find (namespaceName);
craigdo@4151
   192
  if (offset != 0)
craigdo@4141
   193
    {
craigdo@4141
   194
      //
craigdo@4151
   195
      // This must be a name that has the "/Names" namespace prefix omitted.  
craigdo@4151
   196
      // Do some reasonableness checking on the rest of the name.
craigdo@4141
   197
      //
craigdo@4151
   198
      offset = name.find ("/");
craigdo@4151
   199
      if (offset == 0)
craigdo@4151
   200
        {
craigdo@4151
   201
          NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
craigdo@4151
   202
          return false;
craigdo@4151
   203
        }
craigdo@4141
   204
craigdo@4151
   205
      name = "/Names/" + name;
craigdo@4151
   206
    }
craigdo@4151
   207
  
craigdo@4151
   208
  //
craigdo@4159
   209
  // There must now be a fully qualified path in the string.  All fully 
craigdo@4151
   210
  // qualified names begin with "/Names".  We have to split off the final 
craigdo@4159
   211
  // segment which will become the name of the object.  A '/' that
craigdo@4159
   212
  // separates the path from the final segment had better be there since
craigdo@4151
   213
  // we just made sure that at least the namespace name was there.
craigdo@4151
   214
  //
craigdo@4151
   215
  std::string::size_type i = name.rfind ("/");
craigdo@4151
   216
  NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error.  Can't find '/' in name");
craigdo@4141
   217
craigdo@4151
   218
  //
craigdo@4151
   219
  // The slash we found cannot be the slash at the start of the namespaceName.
craigdo@4159
   220
  // This would indicate there is no name in the path at all.  It can be
craigdo@4151
   221
  // any other index.
craigdo@4151
   222
  //
craigdo@4159
   223
  NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
craigdo@4151
   224
craigdo@4151
   225
  //
craigdo@4159
   226
  // We now know where the path string starts and ends, and where the
craigdo@4159
   227
  // name starts and ends.  All we have to do is to call our available
craigdo@4159
   228
  // function for adding a name under a path string.
craigdo@4151
   229
  //
craigdo@4151
   230
  return Add (name.substr (0, i), name.substr (i + 1), object);
craigdo@4139
   231
}
craigdo@4139
   232
craigdo@4139
   233
bool
craigdo@4158
   234
NamesPriv::Add (std::string path, std::string name, Ptr<Object> object)
craigdo@4148
   235
{
craigdo@4158
   236
  if (path == "/Names")
craigdo@4148
   237
    {
craigdo@4148
   238
      return Add (Ptr<Object> (0, false), name, object);
craigdo@4148
   239
    }
craigdo@4158
   240
  return Add (Find (path), name, object);
craigdo@4148
   241
}
craigdo@4148
   242
craigdo@4148
   243
bool
craigdo@4139
   244
NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
craigdo@4139
   245
{
craigdo@4139
   246
  NS_LOG_FUNCTION (context << name << object);
craigdo@4139
   247
craigdo@4139
   248
  if (IsNamed (object))
craigdo@4139
   249
    {
craigdo@4139
   250
      NS_LOG_LOGIC ("Object is already named");
craigdo@4139
   251
      return false;
craigdo@4139
   252
    }
craigdo@4139
   253
craigdo@4139
   254
  NameNode *node = 0;
craigdo@4139
   255
  if (context)
craigdo@4139
   256
    {
craigdo@4139
   257
      node = IsNamed (context);
craigdo@4139
   258
      NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
craigdo@4139
   259
    }
craigdo@4139
   260
  else
craigdo@4139
   261
    {
craigdo@4139
   262
      node = &m_root;
craigdo@4139
   263
    }
craigdo@4139
   264
craigdo@4139
   265
  if (IsDuplicateName (node, name))
craigdo@4139
   266
    {
craigdo@4139
   267
      NS_LOG_LOGIC ("Name is already taken");
craigdo@4139
   268
      return false;
craigdo@4139
   269
    }
craigdo@4139
   270
craigdo@4139
   271
  NameNode *newNode = new NameNode(node, name, object);
craigdo@4139
   272
  node->m_nameMap[name] = newNode;
craigdo@4139
   273
  m_objectMap[object] = newNode;
craigdo@4139
   274
craigdo@4139
   275
  return true;
craigdo@4139
   276
}
craigdo@4139
   277
craigdo@4153
   278
bool
craigdo@4159
   279
NamesPriv::Rename (std::string oldpath, std::string newname)
craigdo@4159
   280
{
craigdo@4159
   281
  NS_LOG_FUNCTION (oldpath << newname);
craigdo@4159
   282
  //
craigdo@4159
   283
  // This is the simple, easy to use version of Rename, so we want it to be 
craigdo@4159
   284
  // flexible.   We don't want to force a user to always type the fully 
craigdo@4159
   285
  // qualified namespace name, so we allow the namespace name to be omitted.
craigdo@4159
   286
  // For example, calling Rename ("Client/ath0", "eth0") should result in 
craigdo@4159
   287
  // exactly the same behavior as Rename ("/Names/Client/ath0", "eth0").
craigdo@4159
   288
  // Calling Rename ("Client", "Router") should have the same effect as 
craigdo@4159
   289
  // Rename ("Names/Client", "Router")
craigdo@4159
   290
  //
craigdo@4159
   291
  // The first thing to do, then, is to "canonicalize" the input string to always
craigdo@4159
   292
  // be a fully qualified path.
craigdo@4159
   293
  //
craigdo@4159
   294
  // If we are given a name that begins with "/Names/" we assume that this is a
craigdo@4159
   295
  // fully qualified path to the object we want to change.  We split the path into 
craigdo@4159
   296
  // path string (cf directory) and and a final segment (cf filename) and then call
craigdo@4159
   297
  // the "Real" Rename.
craigdo@4159
   298
  //
craigdo@4159
   299
  std::string namespaceName = "/Names";
craigdo@4159
   300
  std::string::size_type offset = oldpath.find (namespaceName);
craigdo@4159
   301
  if (offset != 0)
craigdo@4159
   302
    {
craigdo@4159
   303
      //
craigdo@4159
   304
      // This must be a name that has the "/Names" namespace prefix omitted.  
craigdo@4159
   305
      // Do some reasonableness checking on the rest of the name.
craigdo@4159
   306
      //
craigdo@4159
   307
      offset = oldpath.find ("/");
craigdo@4159
   308
      if (offset == 0)
craigdo@4159
   309
        {
craigdo@4159
   310
          NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
craigdo@4159
   311
          return false;
craigdo@4159
   312
        }
craigdo@4159
   313
craigdo@4159
   314
      oldpath = "/Names/" + oldpath;
craigdo@4159
   315
    }
craigdo@4159
   316
  
craigdo@4159
   317
  //
craigdo@4159
   318
  // There must now be a fully qualified path in the oldpath string.  All 
craigdo@4159
   319
  // fully qualified names begin with "/Names".  We have to split off the final 
craigdo@4159
   320
  // segment which will become the name we want to rename.  A '/' that
craigdo@4159
   321
  // separates the path from the final segment (name) had better be there since
craigdo@4159
   322
  // we just made sure that at least the namespace name was there.
craigdo@4159
   323
  //
craigdo@4159
   324
  std::string::size_type i = oldpath.rfind ("/");
craigdo@4159
   325
  NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error.  Can't find '/' in name");
craigdo@4159
   326
craigdo@4159
   327
  //
craigdo@4159
   328
  // The slash we found cannot be the slash at the start of the namespaceName.
craigdo@4159
   329
  // This would indicate there is no name in the path at all.  It can be
craigdo@4159
   330
  // any other index.
craigdo@4159
   331
  //
craigdo@4159
   332
  NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
craigdo@4159
   333
craigdo@4159
   334
  //
craigdo@4159
   335
  // We now know where the path part of the string starts and ends, and where the
craigdo@4159
   336
  // name part starts and ends.  All we have to do is to call our available
craigdo@4159
   337
  // function for creating adding a name under a path string.
craigdo@4159
   338
  //
craigdo@4159
   339
  return Rename (oldpath.substr (0, i), oldpath.substr (i + 1), newname);
craigdo@4159
   340
}
craigdo@4159
   341
craigdo@4159
   342
bool
craigdo@4159
   343
NamesPriv::Rename (std::string path, std::string oldname, std::string newname)
craigdo@4159
   344
{
craigdo@4159
   345
  if (path == "/Names")
craigdo@4159
   346
    {
craigdo@4159
   347
      return Rename (Ptr<Object> (0, false), oldname, newname);
craigdo@4159
   348
    }
craigdo@4159
   349
  return Rename (Find (path), oldname, newname);
craigdo@4159
   350
}
craigdo@4159
   351
craigdo@4159
   352
bool
craigdo@4153
   353
NamesPriv::Rename (Ptr<Object> context, std::string oldname, std::string newname)
craigdo@4153
   354
{
craigdo@4153
   355
  NS_LOG_FUNCTION (context << oldname << newname);
craigdo@4153
   356
craigdo@4153
   357
  NameNode *node = 0;
craigdo@4153
   358
  if (context)
craigdo@4153
   359
    {
craigdo@4153
   360
      node = IsNamed (context);
craigdo@4153
   361
      NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
craigdo@4153
   362
    }
craigdo@4153
   363
  else
craigdo@4153
   364
    {
craigdo@4153
   365
      node = &m_root;
craigdo@4153
   366
    }
craigdo@4153
   367
craigdo@4153
   368
  if (IsDuplicateName (node, newname))
craigdo@4153
   369
    {
craigdo@4153
   370
      NS_LOG_LOGIC ("New name is already taken");
craigdo@4153
   371
      return false;
craigdo@4153
   372
    }
craigdo@4153
   373
craigdo@4153
   374
  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (oldname);
craigdo@4153
   375
  if (i == node->m_nameMap.end ())
craigdo@4153
   376
    {
craigdo@4153
   377
      NS_LOG_LOGIC ("Old name does not exist in name map");
craigdo@4153
   378
      return false;
craigdo@4153
   379
    }
craigdo@4153
   380
  else
craigdo@4153
   381
    {
craigdo@4153
   382
      NS_LOG_LOGIC ("Old name exists in name map");
craigdo@4153
   383
craigdo@4153
   384
      //
craigdo@4153
   385
      // The rename process consists of:
craigdo@4153
   386
      // 1.  Geting the pointer to the name node from the map and remembering it;
craigdo@4153
   387
      // 2.  Removing the map entry corresponding to oldname from the map;
craigdo@4153
   388
      // 3.  Changing the name string in the name node;
craigdo@4153
   389
      // 4.  Adding the name node back in the map under the newname.
craigdo@4153
   390
      //
craigdo@4153
   391
      NameNode *changeNode = i->second;
craigdo@4153
   392
      node->m_nameMap.erase (i);
craigdo@4153
   393
      changeNode->m_name = newname;
craigdo@4153
   394
      node->m_nameMap[newname] = changeNode;
craigdo@4153
   395
      return true;
craigdo@4153
   396
    }
craigdo@4153
   397
}
craigdo@4153
   398
craigdo@4139
   399
std::string
craigdo@4158
   400
NamesPriv::FindName (Ptr<Object> object)
craigdo@4139
   401
{
craigdo@4139
   402
  NS_LOG_FUNCTION (object);
craigdo@4139
   403
craigdo@4139
   404
  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
craigdo@4139
   405
  if (i == m_objectMap.end ())
craigdo@4139
   406
    {
craigdo@4139
   407
      NS_LOG_LOGIC ("Object does not exist in object map");
craigdo@4139
   408
      return "";
craigdo@4139
   409
    }
craigdo@4139
   410
  else
craigdo@4139
   411
    {
craigdo@4139
   412
      NS_LOG_LOGIC ("Object exists in object map");
craigdo@4139
   413
      return i->second->m_name;
craigdo@4139
   414
    }
craigdo@4139
   415
}
craigdo@4139
   416
craigdo@4139
   417
std::string
craigdo@4158
   418
NamesPriv::FindPath (Ptr<Object> object)
craigdo@4139
   419
{
craigdo@4139
   420
  NS_LOG_FUNCTION (object);
craigdo@4139
   421
craigdo@4139
   422
  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
craigdo@4139
   423
  if (i == m_objectMap.end ())
craigdo@4139
   424
    {
craigdo@4139
   425
      NS_LOG_LOGIC ("Object does not exist in object map");
craigdo@4139
   426
      return "";
craigdo@4139
   427
    }
craigdo@4139
   428
craigdo@4139
   429
  NameNode *p = i->second;
craigdo@4139
   430
  NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
craigdo@4139
   431
craigdo@4158
   432
  std::string path;
craigdo@4139
   433
craigdo@4139
   434
  do
craigdo@4139
   435
    {
craigdo@4158
   436
      path = "/" + p->m_name + path;
craigdo@4158
   437
      NS_LOG_LOGIC ("path is " << path);
craigdo@4139
   438
    }
craigdo@4139
   439
  while ((p = p->m_parent) != 0);
craigdo@4139
   440
craigdo@4158
   441
  return path;
craigdo@4139
   442
}
craigdo@4139
   443
craigdo@4139
   444
craigdo@4139
   445
Ptr<Object>
craigdo@4158
   446
NamesPriv::Find (std::string path)
craigdo@4139
   447
{
craigdo@4149
   448
  //
craigdo@4149
   449
  // This is hooked in from simple, easy to use version of Find, so we want it
craigdo@4149
   450
  // to be flexible.
craigdo@4149
   451
  //
craigdo@4158
   452
  // If we are provided a path that doesn't begin with "/Names", we assume 
craigdo@4158
   453
  // that the caller has simply given us a path starting with a name that
craigdo@4149
   454
  // is in the root namespace.  This allows peole to omit the "/Names" prefix.
craigdo@4149
   455
  // and simply do a Find ("Client/eth0") instead of having to always do a
craigdo@4149
   456
  // Find ("/Names/Client/eth0");
craigdo@4149
   457
  //
craigdo@4149
   458
  // So, if we are given a name that begins with "/Names/" the upshot is that we
craigdo@4149
   459
  // just remove that prefix and treat the rest of the string as starting with a 
craigdo@4158
   460
  // name in the root namespace.
craigdo@4149
   461
  //
craigdo@4139
   462
  std::string namespaceName = "/Names/";
craigdo@4149
   463
  std::string remaining;
craigdo@4149
   464
craigdo@4158
   465
  std::string::size_type offset = path.find (namespaceName);
craigdo@4149
   466
  if (offset == 0)
craigdo@4139
   467
    {
craigdo@4158
   468
      NS_LOG_LOGIC (path << " is a fully qualified name");
craigdo@4158
   469
      remaining = path.substr (namespaceName.size ());
craigdo@4149
   470
    }
craigdo@4149
   471
  else
craigdo@4149
   472
    {
craigdo@4159
   473
      NS_LOG_LOGIC (path << " begins with a relative name");
craigdo@4158
   474
      remaining = path;
craigdo@4139
   475
    }
craigdo@4139
   476
craigdo@4139
   477
  NameNode *node = &m_root;
craigdo@4139
   478
craigdo@4139
   479
  //
craigdo@4149
   480
  // The string <remaining> is now composed entirely of path segments in the
craigdo@4149
   481
  // /Names name space and we have eaten the leading slash. e.g., 
craigdo@4149
   482
  // remaining = "ClientNode/eth0"
craigdo@4149
   483
  //
craigdo@4149
   484
  // The start of the search is always at the root of the name space.
craigdo@4139
   485
  //
craigdo@4139
   486
  for (;;)
craigdo@4139
   487
    {
craigdo@4139
   488
      NS_LOG_LOGIC ("Looking for the object of name " << remaining);
craigdo@4139
   489
      offset = remaining.find ("/");
craigdo@4139
   490
      if (offset == std::string::npos)
craigdo@4139
   491
        {
craigdo@4139
   492
          //
craigdo@4139
   493
          // There are no remaining slashes so this is the last segment of the 
craigdo@4139
   494
          // specified name.  We're done when we find it
craigdo@4139
   495
          //
craigdo@4139
   496
          std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
craigdo@4139
   497
          if (i == node->m_nameMap.end ())
craigdo@4139
   498
            {
craigdo@4139
   499
              NS_LOG_LOGIC ("Name does not exist in name map");
craigdo@4139
   500
              return 0;
craigdo@4139
   501
            }
craigdo@4139
   502
          else
craigdo@4139
   503
            {
craigdo@4139
   504
              NS_LOG_LOGIC ("Name parsed, found object");
craigdo@4139
   505
              return i->second->m_object;
craigdo@4139
   506
            }
craigdo@4139
   507
        }
craigdo@4139
   508
      else
craigdo@4139
   509
        {
craigdo@4139
   510
          //
craigdo@4139
   511
          // There are more slashes so this is an intermediate segment of the 
craigdo@4139
   512
          // specified name.  We need to "recurse" when we find this segment.
craigdo@4139
   513
          //
craigdo@4139
   514
          offset = remaining.find ("/");
craigdo@4139
   515
          std::string segment = remaining.substr(0, offset);
craigdo@4139
   516
craigdo@4139
   517
          std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
craigdo@4139
   518
          if (i == node->m_nameMap.end ())
craigdo@4139
   519
            {
craigdo@4139
   520
              NS_LOG_LOGIC ("Name does not exist in name map");
craigdo@4139
   521
              return 0;
craigdo@4139
   522
            }
craigdo@4139
   523
          else
craigdo@4139
   524
            {
craigdo@4139
   525
              node = i->second;
craigdo@4139
   526
              remaining = remaining.substr (offset + 1);
craigdo@4139
   527
              NS_LOG_LOGIC ("Intermediate segment parsed");
craigdo@4139
   528
              continue;
craigdo@4139
   529
            }
craigdo@4139
   530
        }
craigdo@4139
   531
    }
craigdo@4139
   532
craigdo@4158
   533
  NS_ASSERT_MSG (node, "NamesPriv::Find(): Internal error:  this can't happen");
craigdo@4139
   534
  return 0;
craigdo@4139
   535
}
craigdo@4139
   536
craigdo@4139
   537
Ptr<Object>
craigdo@4158
   538
NamesPriv::Find (std::string path, std::string name)
craigdo@4158
   539
{
craigdo@4158
   540
  NS_LOG_FUNCTION (path << name);
craigdo@4158
   541
craigdo@4158
   542
  if (path == "/Names")
craigdo@4158
   543
    {
craigdo@4158
   544
      return Find (Ptr<Object> (0, false), name);
craigdo@4158
   545
    }
craigdo@4158
   546
  return Find (Find (path), name);
craigdo@4158
   547
}
craigdo@4158
   548
craigdo@4158
   549
Ptr<Object>
craigdo@4158
   550
NamesPriv::Find (Ptr<Object> context, std::string name)
craigdo@4139
   551
{
craigdo@4139
   552
  NS_LOG_FUNCTION (context << name);
craigdo@4139
   553
craigdo@4139
   554
  NameNode *node = 0;
craigdo@4139
   555
craigdo@4139
   556
  if (context == 0)
craigdo@4139
   557
    {
craigdo@4139
   558
      NS_LOG_LOGIC ("Zero context implies root NameNode");
craigdo@4139
   559
      node = &m_root;
craigdo@4139
   560
    }
craigdo@4139
   561
  else
craigdo@4139
   562
    {
craigdo@4139
   563
      node = IsNamed (context);
craigdo@4139
   564
      if (node == 0)
craigdo@4139
   565
        {
craigdo@4139
   566
          NS_LOG_LOGIC ("Context does not point to a previously named node");
craigdo@4139
   567
          return 0;
craigdo@4139
   568
        }
craigdo@4139
   569
    }
craigdo@4139
   570
craigdo@4139
   571
  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
craigdo@4139
   572
  if (i == node->m_nameMap.end ())
craigdo@4139
   573
    {
craigdo@4139
   574
      NS_LOG_LOGIC ("Name does not exist in name map");
craigdo@4139
   575
      return 0;
craigdo@4139
   576
    }
craigdo@4139
   577
  else
craigdo@4139
   578
    {
craigdo@4139
   579
      NS_LOG_LOGIC ("Name exists in name map");
craigdo@4139
   580
      return i->second->m_object;
craigdo@4139
   581
    }
craigdo@4139
   582
}
craigdo@4139
   583
craigdo@4139
   584
NameNode *
craigdo@4139
   585
NamesPriv::IsNamed (Ptr<Object> object)
craigdo@4139
   586
{
craigdo@4139
   587
  NS_LOG_FUNCTION (object);
craigdo@4139
   588
craigdo@4139
   589
  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
craigdo@4139
   590
  if (i == m_objectMap.end ())
craigdo@4139
   591
    {
craigdo@4139
   592
      NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
craigdo@4139
   593
      return 0;
craigdo@4139
   594
    }
craigdo@4139
   595
  else
craigdo@4139
   596
    {
craigdo@4139
   597
      NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
craigdo@4139
   598
      return i->second;
craigdo@4139
   599
    }
craigdo@4139
   600
}
craigdo@4139
   601
craigdo@4139
   602
bool
craigdo@4139
   603
NamesPriv::IsDuplicateName (NameNode *node, std::string name)
craigdo@4139
   604
{
craigdo@4139
   605
  NS_LOG_FUNCTION (node << name);
craigdo@4139
   606
craigdo@4139
   607
  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
craigdo@4139
   608
  if (i == node->m_nameMap.end ())
craigdo@4139
   609
    {
craigdo@4139
   610
      NS_LOG_LOGIC ("Name does not exist in name map");
craigdo@4139
   611
      return false;
craigdo@4139
   612
    }
craigdo@4139
   613
  else
craigdo@4139
   614
    {
craigdo@4139
   615
      NS_LOG_LOGIC ("Name exists in name map");
craigdo@4139
   616
      return true;
craigdo@4139
   617
    }
craigdo@4139
   618
}
craigdo@4139
   619
craigdo@4145
   620
void
craigdo@4145
   621
Names::Delete (void)
craigdo@4145
   622
{
craigdo@4145
   623
  NamesPriv::Delete ();
craigdo@4145
   624
}
craigdo@4145
   625
craigdo@4298
   626
void
craigdo@4139
   627
Names::Add (std::string name, Ptr<Object> object)
craigdo@4139
   628
{
craigdo@4298
   629
  bool result = NamesPriv::Get ()->Add (name, object);
craigdo@4298
   630
  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name);
craigdo@4139
   631
}
craigdo@4139
   632
craigdo@4298
   633
void
craigdo@4159
   634
Names::Rename (std::string oldpath, std::string newname)
craigdo@4153
   635
{
craigdo@4298
   636
  bool result = NamesPriv::Get ()->Rename (oldpath, newname);
craigdo@4298
   637
  NS_ABORT_MSG_UNLESS (result, "Names::Rename(): Error renaming " << oldpath << " to " << newname);
craigdo@4153
   638
}
craigdo@4153
   639
craigdo@4298
   640
void
craigdo@4158
   641
Names::Add (std::string path, std::string name, Ptr<Object> object)
craigdo@4158
   642
{
craigdo@4298
   643
  bool result = NamesPriv::Get ()->Add (path, name, object);
craigdo@4298
   644
  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding " << path << " " << name);
craigdo@4158
   645
}
craigdo@4158
   646
craigdo@4298
   647
void
craigdo@4158
   648
Names::Rename (std::string path, std::string oldname, std::string newname)
craigdo@4158
   649
{
craigdo@4298
   650
  bool result = NamesPriv::Get ()->Rename (path, oldname, newname);
craigdo@4298
   651
  NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << path << " " << oldname << " to " << newname);
craigdo@4158
   652
}
craigdo@4158
   653
craigdo@4298
   654
void
craigdo@4139
   655
Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
craigdo@4139
   656
{
craigdo@4298
   657
  bool result = NamesPriv::Get ()->Add (context, name, object);
craigdo@4298
   658
  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name << " under context " << &context);
craigdo@4139
   659
}
craigdo@4139
   660
craigdo@4298
   661
void
craigdo@4153
   662
Names::Rename (Ptr<Object> context, std::string oldname, std::string newname)
craigdo@4153
   663
{
craigdo@4298
   664
  bool result = NamesPriv::Get ()->Rename (context, oldname, newname);
craigdo@4298
   665
  NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << oldname << " to " << newname << " under context " <<
craigdo@4298
   666
                       &context);
craigdo@4153
   667
}
craigdo@4153
   668
craigdo@4158
   669
std::string
craigdo@4158
   670
Names::FindName (Ptr<Object> object)
craigdo@4139
   671
{
craigdo@4158
   672
  return NamesPriv::Get ()->FindName (object);
craigdo@4153
   673
}
craigdo@4153
   674
craigdo@4139
   675
std::string
craigdo@4158
   676
Names::FindPath (Ptr<Object> object)
craigdo@4139
   677
{
craigdo@4158
   678
  return NamesPriv::Get ()->FindPath (object);
craigdo@4139
   679
}
craigdo@4139
   680
craigdo@4139
   681
Ptr<Object>
craigdo@4158
   682
Names::FindInternal (std::string name)
craigdo@4139
   683
{
craigdo@4158
   684
  return NamesPriv::Get ()->Find (name);
craigdo@4139
   685
}
craigdo@4139
   686
craigdo@4139
   687
Ptr<Object>
craigdo@4158
   688
Names::FindInternal (std::string path, std::string name)
craigdo@4139
   689
{
craigdo@4158
   690
  return NamesPriv::Get ()->Find (path, name);
craigdo@4158
   691
}
craigdo@4158
   692
craigdo@4158
   693
Ptr<Object>
craigdo@4158
   694
Names::FindInternal (Ptr<Object> context, std::string name)
craigdo@4158
   695
{
craigdo@4158
   696
  return NamesPriv::Get ()->Find (context, name);
craigdo@4139
   697
}
craigdo@4139
   698
craigdo@4139
   699
} //namespace ns3
craigdo@4139
   700
craigdo@4139
   701
#ifdef RUN_SELF_TESTS
craigdo@4139
   702
craigdo@4139
   703
#include "test.h"
craigdo@4139
   704
#include "object-factory.h"
craigdo@4139
   705
craigdo@4139
   706
namespace ns3 {
craigdo@4139
   707
craigdo@4139
   708
class TestObject : public Object
craigdo@4139
   709
{
craigdo@4139
   710
public:
craigdo@4139
   711
  static TypeId GetTypeId (void) 
craigdo@4139
   712
  {
craigdo@4139
   713
    static TypeId tid = TypeId ("TestObject")
craigdo@4139
   714
      .SetParent (Object::GetTypeId ())
craigdo@4139
   715
      .HideFromDocumentation ()
craigdo@4139
   716
      .AddConstructor<TestObject> ();
craigdo@4139
   717
    return tid;
craigdo@4139
   718
  }
craigdo@4139
   719
  TestObject () {}
craigdo@4139
   720
  virtual void Dispose (void) {}
craigdo@4139
   721
};
craigdo@4139
   722
craigdo@4139
   723
class NamesTest : public Test
craigdo@4139
   724
{
craigdo@4139
   725
public:
craigdo@4139
   726
  NamesTest ();
craigdo@4139
   727
  virtual bool RunTests (void);
craigdo@4139
   728
};
craigdo@4139
   729
craigdo@4139
   730
NamesTest::NamesTest ()
craigdo@4139
   731
  : Test ("Names")
craigdo@4139
   732
{
craigdo@4139
   733
}
craigdo@4139
   734
craigdo@4139
   735
bool 
craigdo@4139
   736
NamesTest::RunTests (void)
craigdo@4139
   737
{
craigdo@4139
   738
  bool result = true;
craigdo@4139
   739
craigdo@4298
   740
  //
craigdo@4298
   741
  // Names::Add and Names::Rename return void to align with the Config API.
craigdo@4298
   742
  // The private versions of these functions do return error codes so we
craigdo@4298
   743
  // can test to make sure errors are detected.  Names::Add and 
craigdo@4298
   744
  // Names::Rename check for these error codes and abort if an error was
craigdo@4298
   745
  // detected.  So when we expect that an error should be detected, we 
craigdo@4298
   746
  // have to call the private routine to avoid a fatal error popping.
craigdo@4139
   747
  // 
craigdo@4139
   748
  // Name a couple of objects at the root level
craigdo@4139
   749
  //
craigdo@4139
   750
  Ptr<TestObject> client = CreateObject<TestObject> ();
craigdo@4298
   751
  Names::Add ("Client", client);
craigdo@4139
   752
craigdo@4139
   753
  Ptr<TestObject> server = CreateObject<TestObject> ();
craigdo@4298
   754
  Names::Add ("Server", server);
craigdo@4139
   755
craigdo@4139
   756
  //
craigdo@4139
   757
  // We shouldn't be able to add another name to a previously named object
craigdo@4139
   758
  //
craigdo@4298
   759
  result = NamesPriv::Get ()->Add ("Not Client", client);
craigdo@4139
   760
  NS_TEST_ASSERT_EQUAL (result, false);
craigdo@4139
   761
craigdo@4139
   762
  //
craigdo@4139
   763
  // We shouldn't be able to duplicate a name at the root level.
craigdo@4139
   764
  //
craigdo@4139
   765
  Ptr<TestObject> secondClient = CreateObject<TestObject> ();
craigdo@4298
   766
  result = NamesPriv::Get ()->Add ("Client", secondClient);
craigdo@4139
   767
  NS_TEST_ASSERT_EQUAL (result, false);
craigdo@4139
   768
craigdo@4139
   769
  //
craigdo@4139
   770
  // We should be able to add a new name in the first object's context
craigdo@4139
   771
  //
craigdo@4139
   772
  Ptr<TestObject> clientEth0 = CreateObject<TestObject> ();
craigdo@4298
   773
  Names::Add (client, "eth0", clientEth0);
craigdo@4139
   774
craigdo@4139
   775
  //
craigdo@4139
   776
  // We shouldn't be able to duplicate a name in that context.
craigdo@4139
   777
  //
craigdo@4139
   778
  Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> ();
craigdo@4298
   779
  result = NamesPriv::Get ()->Add (client, "eth0", secondClientEth0);
craigdo@4139
   780
  NS_TEST_ASSERT_EQUAL (result, false);
craigdo@4139
   781
craigdo@4139
   782
  //
craigdo@4139
   783
  // We should be able to add the same name in the second object's context
craigdo@4139
   784
  //
craigdo@4139
   785
  Ptr<TestObject> serverEth0 = CreateObject<TestObject> ();
craigdo@4298
   786
  Names::Add (server, "eth0", serverEth0);
craigdo@4139
   787
craigdo@4139
   788
  //
craigdo@4139
   789
  // We should be able to find the short names for the objects we created
craigdo@4139
   790
  //
craigdo@4139
   791
  std::string found;
craigdo@4139
   792
craigdo@4158
   793
  found = Names::FindName (client);
craigdo@4139
   794
  NS_TEST_ASSERT_EQUAL (found, "Client");
craigdo@4139
   795
craigdo@4158
   796
  found = Names::FindName (server);
craigdo@4139
   797
  NS_TEST_ASSERT_EQUAL (found, "Server");
craigdo@4139
   798
craigdo@4158
   799
  found = Names::FindName (clientEth0);
craigdo@4139
   800
  NS_TEST_ASSERT_EQUAL (found, "eth0");
craigdo@4139
   801
craigdo@4158
   802
  found = Names::FindName (serverEth0);
craigdo@4139
   803
  NS_TEST_ASSERT_EQUAL (found, "eth0");
craigdo@4139
   804
craigdo@4139
   805
  //
craigdo@4139
   806
  // We should be able to find the full names for the objects we created
craigdo@4139
   807
  //
craigdo@4158
   808
  found = Names::FindPath (client);
craigdo@4139
   809
  NS_TEST_ASSERT_EQUAL (found, "/Names/Client");
craigdo@4139
   810
craigdo@4158
   811
  found = Names::FindPath (server);
craigdo@4139
   812
  NS_TEST_ASSERT_EQUAL (found, "/Names/Server");
craigdo@4139
   813
craigdo@4158
   814
  found = Names::FindPath (clientEth0);
craigdo@4139
   815
  NS_TEST_ASSERT_EQUAL (found, "/Names/Client/eth0");
craigdo@4139
   816
craigdo@4158
   817
  found = Names::FindPath (serverEth0);
craigdo@4139
   818
  NS_TEST_ASSERT_EQUAL (found, "/Names/Server/eth0");
craigdo@4139
   819
craigdo@4139
   820
  // 
craigdo@4159
   821
  // We should be able to find the objects from a context and name combination.
craigdo@4159
   822
  // Note that the Ptr<Object> (0, false) below is to differentiate a null object
craigdo@4159
   823
  // pointer from a null string pointer -- not normally needed in real use-cases.
craigdo@4158
   824
  // 
craigdo@4139
   825
  //
craigdo@4139
   826
  Ptr<TestObject> foundObject;
craigdo@4139
   827
craigdo@4158
   828
  foundObject = Names::Find<TestObject> (Ptr<Object> (0, false), "Client");
craigdo@4139
   829
  NS_TEST_ASSERT_EQUAL (foundObject, client);
craigdo@4139
   830
craigdo@4158
   831
  foundObject = Names::Find<TestObject> (Ptr<Object> (0, false), "Server");
craigdo@4139
   832
  NS_TEST_ASSERT_EQUAL (foundObject, server);
craigdo@4139
   833
craigdo@4158
   834
  foundObject = Names::Find<TestObject> (client, "eth0");
craigdo@4139
   835
  NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
craigdo@4139
   836
craigdo@4158
   837
  foundObject = Names::Find<TestObject> (server, "eth0");
craigdo@4139
   838
  NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
craigdo@4139
   839
craigdo@4159
   840
  //
craigdo@4159
   841
  // We should be able to do the same thing by providing path strings instead
craigdo@4159
   842
  // of context objects.
craigdo@4159
   843
  //
craigdo@4159
   844
craigdo@4159
   845
  foundObject = Names::Find<TestObject> ("/Names", "Client");
craigdo@4159
   846
  NS_TEST_ASSERT_EQUAL (foundObject, client);
craigdo@4159
   847
craigdo@4159
   848
  foundObject = Names::Find<TestObject> ("/Names", "Server");
craigdo@4159
   849
  NS_TEST_ASSERT_EQUAL (foundObject, server);
craigdo@4159
   850
craigdo@4159
   851
  foundObject = Names::Find<TestObject> ("/Names/Client", "eth0");
craigdo@4159
   852
  NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
craigdo@4159
   853
craigdo@4159
   854
  foundObject = Names::Find<TestObject> ("/Names/Server", "eth0");
craigdo@4159
   855
  NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
craigdo@4159
   856
craigdo@4139
   857
  // 
craigdo@4158
   858
  // We should be able to find the objects from their full path names
craigdo@4139
   859
  //
craigdo@4139
   860
  foundObject = Names::Find<TestObject> ("/Names/Client");
craigdo@4139
   861
  NS_TEST_ASSERT_EQUAL (foundObject, client);
craigdo@4139
   862
craigdo@4139
   863
  foundObject = Names::Find<TestObject> ("/Names/Server");
craigdo@4139
   864
  NS_TEST_ASSERT_EQUAL (foundObject, server);
craigdo@4139
   865
craigdo@4139
   866
  foundObject = Names::Find<TestObject> ("/Names/Client/eth0");
craigdo@4139
   867
  NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
craigdo@4139
   868
craigdo@4139
   869
  foundObject = Names::Find<TestObject> ("/Names/Server/eth0");
craigdo@4139
   870
  NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
craigdo@4139
   871
craigdo@4149
   872
  // 
craigdo@4158
   873
  // We should be able to omit the root of the namespace from the full path names
craigdo@4149
   874
  //
craigdo@4149
   875
  foundObject = Names::Find<TestObject> ("Client");
craigdo@4149
   876
  NS_TEST_ASSERT_EQUAL (foundObject, client);
craigdo@4149
   877
craigdo@4149
   878
  foundObject = Names::Find<TestObject> ("Server");
craigdo@4149
   879
  NS_TEST_ASSERT_EQUAL (foundObject, server);
craigdo@4149
   880
craigdo@4149
   881
  foundObject = Names::Find<TestObject> ("Client/eth0");
craigdo@4149
   882
  NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
craigdo@4149
   883
craigdo@4149
   884
  foundObject = Names::Find<TestObject> ("Server/eth0");
craigdo@4149
   885
  NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
craigdo@4149
   886
craigdo@4139
   887
  //
craigdo@4151
   888
  // We should be able to add objects while including the root of the namespace
craigdo@4151
   889
  // in the name.
craigdo@4151
   890
  //
craigdo@4151
   891
  Ptr<TestObject> router1 = CreateObject<TestObject> ();
craigdo@4298
   892
  Names::Add ("/Names/Router1", router1);
craigdo@4151
   893
craigdo@4151
   894
  //
craigdo@4151
   895
  // We should be able to add objects while not including the root of the namespace
craigdo@4151
   896
  // in the name.
craigdo@4151
   897
  //
craigdo@4151
   898
  Ptr<TestObject> router2 = CreateObject<TestObject> ();
craigdo@4298
   899
  Names::Add ("Router2", router2);
craigdo@4151
   900
craigdo@4151
   901
  //
craigdo@4151
   902
  // We should be able to add sub-objects while including the root of the namespace
craigdo@4151
   903
  // in the name.
craigdo@4151
   904
  //
craigdo@4151
   905
  Ptr<TestObject> router1Eth0 = CreateObject<TestObject> ();
craigdo@4298
   906
  Names::Add ("/Names/Router1/eth0", router1Eth0);
craigdo@4151
   907
craigdo@4151
   908
  //
craigdo@4151
   909
  // We should be able to add sub-objects while not including the root of the namespace
craigdo@4151
   910
  // in the name.
craigdo@4151
   911
  //
craigdo@4151
   912
  Ptr<TestObject> router2Eth0 = CreateObject<TestObject> ();
craigdo@4298
   913
  Names::Add ("Router2/eth0", router2Eth0);
craigdo@4151
   914
craigdo@4151
   915
  //
craigdo@4151
   916
  // We should be able to find these objects in the same two ways
craigdo@4151
   917
  //
craigdo@4151
   918
  foundObject = Names::Find<TestObject> ("/Names/Router1");
craigdo@4151
   919
  NS_TEST_ASSERT_EQUAL (foundObject, router1);
craigdo@4151
   920
craigdo@4151
   921
  foundObject = Names::Find<TestObject> ("Router1");
craigdo@4151
   922
  NS_TEST_ASSERT_EQUAL (foundObject, router1);
craigdo@4151
   923
craigdo@4151
   924
  foundObject = Names::Find<TestObject> ("/Names/Router2");
craigdo@4151
   925
  NS_TEST_ASSERT_EQUAL (foundObject, router2);
craigdo@4151
   926
craigdo@4151
   927
  foundObject = Names::Find<TestObject> ("Router2");
craigdo@4151
   928
  NS_TEST_ASSERT_EQUAL (foundObject, router2);
craigdo@4151
   929
craigdo@4151
   930
  foundObject = Names::Find<TestObject> ("/Names/Router1/eth0");
craigdo@4151
   931
  NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
craigdo@4151
   932
craigdo@4151
   933
  foundObject = Names::Find<TestObject> ("Router1/eth0");
craigdo@4151
   934
  NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
craigdo@4151
   935
craigdo@4151
   936
  foundObject = Names::Find<TestObject> ("/Names/Router2/eth0");
craigdo@4151
   937
  NS_TEST_ASSERT_EQUAL (foundObject, router2Eth0);
craigdo@4151
   938
craigdo@4151
   939
  foundObject = Names::Find<TestObject> ("Router2/eth0");
craigdo@4151
   940
  NS_TEST_ASSERT_EQUAL (foundObject, router2Eth0);
craigdo@4151
   941
craigdo@4151
   942
  //
craigdo@4153
   943
  // We have a pile of names defined.  We should be able to rename them in the
craigdo@4153
   944
  // usual ways.
craigdo@4153
   945
  //
craigdo@4298
   946
  Names::Rename ("/Names/Router1", "RouterX");
craigdo@4153
   947
craigdo@4153
   948
  foundObject = Names::Find<TestObject> ("/Names/RouterX");
craigdo@4153
   949
  NS_TEST_ASSERT_EQUAL (foundObject, router1);
craigdo@4153
   950
craigdo@4298
   951
  Names::Rename ("Router2", "RouterY");
craigdo@4153
   952
craigdo@4153
   953
  foundObject = Names::Find<TestObject> ("RouterY");
craigdo@4153
   954
  NS_TEST_ASSERT_EQUAL (foundObject, router2);
craigdo@4153
   955
craigdo@4298
   956
  Names::Rename ("/Names/RouterX/eth0", "ath0");
craigdo@4153
   957
craigdo@4153
   958
  foundObject = Names::Find<TestObject> ("/Names/RouterX/ath0");
craigdo@4153
   959
  NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
craigdo@4153
   960
craigdo@4153
   961
  foundObject = Names::Find<TestObject> ("RouterX/ath0");
craigdo@4153
   962
  NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
craigdo@4153
   963
craigdo@4153
   964
  //
craigdo@4153
   965
  // We should not be able to rename an object into conflict with another
craigdo@4153
   966
  // object.
craigdo@4153
   967
  //
craigdo@4153
   968
craigdo@4298
   969
  result = NamesPriv::Get ()->Rename ("/Names/RouterX", "RouterY");
craigdo@4153
   970
  NS_TEST_ASSERT_EQUAL (result, false);
craigdo@4153
   971
craigdo@4161
   972
  Names::Delete ();
craigdo@4139
   973
  return true;
craigdo@4139
   974
}
craigdo@4139
   975
craigdo@4139
   976
static NamesTest g_namesTests;
craigdo@4139
   977
craigdo@4139
   978
} // namespace ns3
craigdo@4139
   979
craigdo@4139
   980
#endif /* RUN_SELF_TESTS */