Merge pull request #2303 from jwillemsen/jwi-803
[ACE_TAO.git] / TAO / utils / nslist / nslist.cpp
blobb3670dc4291cd48bc2610eb3fb4558457777d05a
1 //=============================================================================
2 /**
3 * @file nslist.cpp
5 * Naming Service listing utility
7 * @author Thomas Lockhart, NASA/JPL <Thomas.Lockhart@jpl.nasa.gov>
8 * @date 1999-06-03
9 * Enhanced 21 Jun, 2006 Simon Massey <sma@prismtech.com>
11 //=============================================================================
13 #include "ace/SString.h"
14 #include "orbsvcs/CosNamingC.h"
15 #include "orbsvcs/Time_Utilities.h"
16 #include "tao/Endpoint.h"
17 #include "tao/Profile.h"
18 #include "tao/Stub.h"
19 #include "tao/ORB_Constants.h"
20 #include "tao/AnyTypeCode/Any.h"
21 #include "tao/Messaging/Messaging.h"
22 #include "tao/Strategies/advanced_resource.h"
23 #include "tao/PolicyC.h"
24 #include "ace/Time_Value.h"
25 #include "ace/Log_Msg.h"
26 #include "ace/OS_NS_stdio.h"
27 #include "ace/Argv_Type_Converter.h"
28 #include "ace/OS_NS_ctype.h"
30 //============================================================================
31 namespace
33 CORBA::ORB_var orb;
34 bool
35 showIOR = false, // Default decodes endpoints
36 showCtxIOR = false, // Default no displaying naming context ior
37 noLoops = false; // Default draw loopback arrows
38 const char
39 *myTree = "|", // Default string to draw tree "tram-lines"
40 *myNode = "+"; // Default string to draw tree node end-points
41 size_t sizeMyTree; // Initialised by main to strlen (myTree)
42 size_t sizeMyNode; // Initialised by main to strlen (myNode)
43 size_t maxDepth= 0; // Limit to display depth (default unlimited)
44 ACE_Time_Value
45 rtt = ACE_Time_Value::zero; // relative roundtrip timeout for ctx
47 const CORBA::ULong MAX_COUNT_DEFAULT = 100;
48 CORBA::ULong max_count = MAX_COUNT_DEFAULT;
50 void list_context (const CosNaming::NamingContext_ptr,
51 size_t level,
52 CORBA::ULong max_count);
54 CORBA::Object_ptr set_rtt(CORBA::Object_ptr obj);
56 //==========================================================================
57 class NestedNamingContexts
59 public:
60 static void add (const CosNaming::NamingContext_ptr nc)
62 (void) new NestedNamingContexts( nc ); // This is not a leak (see constructor)
65 static void remove ()
67 delete pBottom;
70 static size_t hasBeenSeen (const CosNaming::NamingContext_ptr nc)
72 size_t level = 1;
73 for (const NestedNamingContexts *pMyNode= pBottom;
74 pMyNode;
75 ++level, pMyNode= pMyNode->pNext)
77 if (pMyNode->pnc->_is_equivalent (nc))
78 return level; // Loops backwards this number of levels
81 return 0; // Not seen before
84 private:
85 static const NestedNamingContexts
86 *pBottom; // Our current lowest level
87 const CosNaming::NamingContext_ptr
88 pnc; // This level's Naming Context
89 const NestedNamingContexts
90 *const pNext; // Next highest level
92 NestedNamingContexts (const CosNaming::NamingContext_ptr nc)
93 :pnc(nc), pNext(pBottom) // Adds the old list to this!
95 this->pBottom= this; // Doesn't leak this (it's the new start)
98 ~NestedNamingContexts ()
100 this->pBottom= this->pNext; // this node removed from list.
103 // Outlaw copying
104 NestedNamingContexts (const NestedNamingContexts &);
105 NestedNamingContexts &operator= (const NestedNamingContexts &);
107 const NestedNamingContexts *NestedNamingContexts::pBottom= 0;
109 //==========================================================================
110 void
111 get_tag_name (CORBA::ULong tag, ACE_CString& tag_string)
113 if (tag == IOP::TAG_INTERNET_IOP)
114 tag_string = "IIOP";
115 else if (tag == TAO_TAG_UIOP_PROFILE)
116 tag_string = "UIOP";
117 else if (tag == TAO_TAG_SHMEM_PROFILE)
118 tag_string = "SHMEM";
119 else if (tag == TAO_TAG_DIOP_PROFILE)
120 tag_string = "DIOP";
121 else if (tag == TAO_TAG_COIOP_PROFILE)
122 tag_string = "COIOP";
123 else if (tag == TAO_TAG_SCIOP_PROFILE)
124 tag_string = "SCIOP";
125 else
127 char buffer[32]= {'\0'};
128 ACE_OS::sprintf( buffer, "%08x (%u)", tag, tag );
129 (tag_string = "Unknown tag: ") += buffer;
133 //==========================================================================
134 void
135 display_endpoint_info (CORBA::Object_ptr obj, const size_t level)
137 TAO_Stub *stub = obj->_stubobj ();
138 if (!stub)
140 ACE_DEBUG ((LM_DEBUG, " {Invalid Stub}\n"));
141 return;
144 TAO_Profile* profile = stub->profile_in_use ();
145 if (!profile)
147 ACE_DEBUG ((LM_DEBUG, " {Invalid Profile}\n"));
148 return;
151 TAO_Endpoint* endpoint = profile->endpoint ();
152 if (!endpoint)
154 ACE_DEBUG ((LM_DEBUG, " {Invalid Endpoint}\n"));
155 return;
158 // Display protocol
159 CORBA::ULong const tag = endpoint->tag ();
160 ACE_CString tag_name;
161 get_tag_name (tag, tag_name);
163 ACE_DEBUG ((LM_DEBUG, "\n"));
164 size_t count;
165 for (count= 0; count < level; ++count)
166 ACE_DEBUG ((LM_DEBUG, "%C ", myTree));
167 for (count= 0; count < sizeMyNode; ++count)
168 ACE_DEBUG ((LM_DEBUG, " "));
169 ACE_DEBUG ((LM_DEBUG, " Protocol: %C\n",
170 tag_name.c_str()));
172 // Display Endpoint
173 for (count= 0; count < level; ++count)
174 ACE_DEBUG ((LM_DEBUG, "%C ", myTree));
175 for (count= 0; count < sizeMyNode; ++count)
176 ACE_DEBUG ((LM_DEBUG, " "));
177 char buf[256]= {'\0'};
178 if (endpoint->addr_to_string (buf, sizeof(buf)-1u) < 0)
179 ACE_OS::strcpy( buf, "{Endpoint too long}" );
180 ACE_DEBUG ((LM_DEBUG, " Endpoint: %C\n", buf));
183 //==========================================================================
184 // Display NS entries from a finite list.
185 void
186 show_chunk (const CosNaming::NamingContext_ptr nc,
187 const CosNaming::BindingList &bl,
188 size_t level)
190 for (CORBA::ULong i = 0;
191 i < bl.length ();
192 ++i)
194 size_t count;
195 for (count= 0; count < level-1; ++count)
196 ACE_DEBUG ((LM_DEBUG, "%C ", myTree));
197 ACE_DEBUG ((LM_DEBUG, "%C %C", myNode,
198 bl[i].binding_name[0].id.in ()));
200 if (bl[i].binding_name[0].kind[0])
201 ACE_DEBUG ((LM_DEBUG,
202 " (Kind: %C)",
203 bl[i].binding_name[0].kind.in ()));
205 CosNaming::Name Name;
206 Name.length (1);
207 Name[0].id =
208 CORBA::string_dup (bl[i].binding_name[0].id);
209 Name[0].kind =
210 CORBA::string_dup (bl[i].binding_name[0].kind);
212 CORBA::Object_var obj = nc->resolve (Name);
214 // If this is a context node, follow it down to the next level...
215 if (bl[i].binding_type == CosNaming::ncontext)
217 ACE_DEBUG ((LM_DEBUG, ": Naming context"));
219 obj = set_rtt(obj.in ());
221 CosNaming::NamingContext_var xc;
224 xc = CosNaming::NamingContext::_narrow (obj.in ());
226 catch (const CORBA::OBJECT_NOT_EXIST&)
228 xc= 0;
229 ACE_DEBUG ((LM_DEBUG, " {Destroyed}"));
231 catch (const CORBA::TRANSIENT&)
233 xc= 0;
234 ACE_DEBUG ((LM_DEBUG, " {Transient context IOR}"));
236 catch (const CORBA::TIMEOUT&)
238 xc= 0;
239 ACE_DEBUG ((LM_DEBUG, " {Operation on conext IOR timed out}"));
242 if (const size_t backwards= NestedNamingContexts::hasBeenSeen (xc.in ()))
244 ACE_DEBUG ((LM_DEBUG, " (Binding Loop)\n"));
245 if (!noLoops)
247 size_t count;
248 for (count= 0; count < (level - backwards); ++count)
249 ACE_DEBUG ((LM_DEBUG, "%C ", myTree));
250 ACE_DEBUG ((LM_DEBUG, "^"));
251 size_t chars;
252 while (++count < level)
253 for (chars= 0; chars <= sizeMyTree; ++chars)
254 ACE_DEBUG ((LM_DEBUG, "-"));
255 for (chars= 0; chars < sizeMyNode; ++chars)
256 ACE_DEBUG ((LM_DEBUG, "-"));
257 ACE_DEBUG ((LM_DEBUG, "^\n"));
260 else
262 if (showCtxIOR)
264 CORBA::String_var str =
265 orb->object_to_string (obj.in ());
266 ACE_DEBUG ((LM_DEBUG, ": %C", str.in ()));
269 if (maxDepth != level)
271 ACE_DEBUG ((LM_DEBUG, "\n"));
272 if (xc.in ())
274 list_context (xc.in (), level + 1, max_count);
277 else
278 ACE_DEBUG ((LM_DEBUG, " {Max depth reached}\n"));
281 // Mark this node as a reference
282 else
284 ACE_DEBUG ((LM_DEBUG, ": Object Reference"));
285 if (CORBA::is_nil (obj.in ()))
286 ACE_DEBUG ((LM_DEBUG, " {Null}"));
288 if (showIOR)
290 CORBA::String_var str =
291 orb->object_to_string (obj.in ());
292 ACE_DEBUG ((LM_DEBUG, ": %C\n", str.in ()));
294 else if (CORBA::is_nil (obj.in ()))
295 ACE_DEBUG ((LM_DEBUG, "\n"));
296 else
297 display_endpoint_info (obj.in(), level);
302 //==========================================================================
303 void
304 list_context (const CosNaming::NamingContext_ptr nc,
305 size_t level,
306 CORBA::ULong max_count)
308 CosNaming::BindingIterator_var it;
309 CosNaming::BindingList_var bl;
311 NestedNamingContexts::add (nc);
312 nc->list (max_count, bl, it);
314 show_chunk (nc, bl.in (), level);
316 if (!CORBA::is_nil (it.in ()))
318 CORBA::Boolean more;
322 more = it->next_n (max_count, bl);
323 show_chunk (nc, bl.in (), level);
324 } while (more);
326 it->destroy ();
329 NestedNamingContexts::remove ();
332 //==========================================================================
333 CORBA::Object_ptr
334 set_rtt(CORBA::Object_ptr obj)
336 if (rtt != ACE_Time_Value::zero)
338 #if defined (TAO_HAS_CORBA_MESSAGING) && TAO_HAS_CORBA_MESSAGING != 0
339 TimeBase::TimeT roundTripTimeoutVal;
340 ORBSVCS_Time::Time_Value_to_TimeT(roundTripTimeoutVal, rtt);
342 CORBA::Any anyObjectVal;
343 anyObjectVal <<= roundTripTimeoutVal;
344 CORBA::PolicyList polList (1);
345 polList.length (1);
347 polList[0] = orb->create_policy(Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE,
348 anyObjectVal);
350 CORBA::Object_var obj2 = obj->_set_policy_overrides(polList, CORBA::SET_OVERRIDE);
351 polList[0]->destroy();
352 return obj2._retn();
353 #else
354 ACE_DEBUG ((LM_DEBUG, "RTT not supported in TAO build.\n"));
355 #endif
357 return CORBA::Object::_duplicate(obj);
359 } // end of local unnamed namespace
361 //============================================================================
363 ACE_TMAIN (int argc, ACE_TCHAR *argv[])
365 int err = 0;
369 // Contact the orb
370 orb = CORBA::ORB_init (argc, argv);
372 // Scan through the command line options
373 bool
374 failed = false,
375 showNSonly = false;
376 ACE_TCHAR kindsep = ACE_TEXT('.');
377 ACE_TCHAR ctxsep[] = ACE_TEXT("/");
378 ACE_TCHAR *name = 0;
379 const ACE_TCHAR *const pname = argv[0];
380 const ACE_TCHAR *nameService = 0;
382 if (0 < argc)
384 while (0 < --argc)
386 ++argv;
387 if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--ns")))
389 if (!--argc)
391 ACE_DEBUG ((LM_DEBUG,
392 "Error: --ns requires an argument\n"));
393 failed = true;
395 else
397 ++argv;
398 if (nameService)
400 ACE_DEBUG ((LM_DEBUG,
401 "Error: more than one --ns.\n"));
402 failed = true;
404 else if (showNSonly)
406 ACE_DEBUG ((LM_DEBUG,
407 "Error: --nsior and --ns "
408 "are both specified\n"));
409 failed = true;
411 else
412 nameService = *argv;
415 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--nsior")))
417 if (showIOR || showCtxIOR || noLoops
418 || nameService || name || maxDepth)
420 ACE_DEBUG ((LM_DEBUG,
421 "Error: --nsior given "
422 "with other options\n"));
423 failed = true;
425 else
426 showNSonly = true;
428 else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--ior")))
430 if (showNSonly)
432 ACE_DEBUG ((LM_DEBUG,
433 "Error: --nsior and --ior are "
434 "both specified\n"));
435 failed = true;
437 else
438 showIOR = true;
440 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--ctxior")))
442 if (showNSonly)
444 ACE_DEBUG ((LM_DEBUG,
445 "Error: --nsior and --ctxior are "
446 "both specified\n"));
447 failed = true;
449 else
450 showCtxIOR = true;
452 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--tree")))
454 if (!--argc)
456 ACE_DEBUG ((LM_DEBUG,
457 "Error: --tree requires an argument\n"));
458 failed = true;
460 else
462 ++argv;
463 if (showNSonly)
465 ACE_DEBUG ((LM_DEBUG,
466 "Error: --nsior and --tree are "
467 "both specified\n"));
468 failed = true;
470 else
471 myTree = ACE_TEXT_ALWAYS_CHAR (*argv);
474 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--node")))
476 if (!--argc)
478 ACE_DEBUG ((LM_DEBUG,
479 "Error: --node requires an argument\n"));
480 failed = true;
482 else
484 ++argv;
485 if (showNSonly)
487 ACE_DEBUG ((LM_DEBUG,
488 "Error: --nsior and --node are "
489 "both specified\n"));
490 failed = true;
492 else
493 myNode = ACE_TEXT_ALWAYS_CHAR (*argv);
496 else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--noloops")))
498 if (showNSonly)
500 ACE_DEBUG ((LM_DEBUG,
501 "Error: --nsior and --noloops are "
502 "both specified\n"));
503 failed = true;
505 else
506 noLoops = true;
508 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--name")))
510 if (name)
512 ACE_DEBUG ((LM_DEBUG,
513 "Error: more than one --name\n"));
514 failed = true;
516 else if (!--argc)
518 ACE_DEBUG ((LM_DEBUG,
519 "Error: --name requires an argument\n"));
520 failed = true;
522 else
524 ++argv;
525 if (showNSonly)
527 ACE_DEBUG ((LM_DEBUG,
528 "Error: --nsior and --name are "
529 "both specified\n"));
530 failed = true;
532 else
533 name = *argv;
536 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--ctxsep")))
538 if (!--argc)
540 ACE_DEBUG ((LM_DEBUG,
541 "Error: --ctxsep requires a character\n"));
542 failed = true;
544 else if (1 != ACE_OS::strlen(*(++argv)))
546 ACE_DEBUG ((LM_DEBUG,
547 "Error: --ctxsep takes a single character (not %s)\n", *argv));
548 failed = true;
550 else if (showNSonly)
552 ACE_DEBUG ((LM_DEBUG,
553 "Error: --nsior and --ctxsep are "
554 "both specified\n"));
555 failed = true;
557 else
558 ctxsep[0] = (*argv)[0];
560 else if (0 == ACE_OS::strcmp (*argv, ACE_TEXT ("--kindsep")))
562 if (!--argc)
564 ACE_DEBUG ((LM_DEBUG,
565 "Error: --kindsep requires a character\n"));
566 failed = true;
568 else if (1 != ACE_OS::strlen(*(++argv)))
570 ACE_DEBUG ((LM_DEBUG,
571 ACE_TEXT ("Error: --kindsep takes a single ")
572 ACE_TEXT ("character (not %s)\n"), *argv));
573 failed = true;
575 else if (showNSonly)
577 ACE_DEBUG ((LM_DEBUG,
578 ACE_TEXT ("Error: --nsior and --kindsep are ")
579 ACE_TEXT ("both specified\n")));
580 failed = true;
582 else
583 kindsep = (*argv)[0];
585 else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--max")))
587 if (maxDepth)
589 ACE_DEBUG ((LM_DEBUG,
590 "Error: --max given more than once\n"));
591 failed = true;
593 else if (!--argc || !ACE_OS::ace_isdigit (ACE_TEXT_ALWAYS_CHAR (*(++argv))[0]))
595 ACE_DEBUG ((LM_DEBUG,
596 ACE_TEXT ("Error: --max requires a number\n")));
597 failed = true;
599 else if (showNSonly)
601 ACE_DEBUG ((LM_DEBUG,
602 ACE_TEXT ("Error: --nsior and --max are ")
603 ACE_TEXT ("both specified\n")));
604 failed = true;
606 else
607 maxDepth= ACE_OS::atoi (*argv);
609 else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--rtt")))
611 if (rtt != ACE_Time_Value::zero)
613 ACE_DEBUG ((LM_DEBUG,
614 ACE_TEXT ("Error: --rtt given more than once\n")));
615 failed = true;
617 else if (!--argc || !ACE_OS::ace_isdigit (ACE_TEXT_ALWAYS_CHAR (*(++argv))[0]))
619 ACE_DEBUG ((LM_DEBUG,
620 ACE_TEXT ("Error: --rtt requires a number\n")));
621 failed = true;
623 else
624 rtt.set (ACE_OS::atoi (*argv), 0);
626 else if (0 == ACE_OS::strcmp(*argv, ACE_TEXT ("--count")))
628 if (max_count != MAX_COUNT_DEFAULT)
630 ACE_DEBUG ((LM_DEBUG,
631 ACE_TEXT ("Error: --count given more than once\n")));
632 failed = true;
634 else if (!--argc || !ACE_OS::ace_isdigit (ACE_TEXT_ALWAYS_CHAR (*(++argv))[0]))
636 ACE_DEBUG ((LM_DEBUG,
637 ACE_TEXT ("Error: --count requires a number\n")));
638 failed = true;
640 else
642 CORBA::ULong count = ACE_OS::strtoul (ACE_TEXT_ALWAYS_CHAR (*argv), 0, 10);
643 if (count > 0)
645 max_count = count;
647 else
649 ACE_DEBUG ((LM_DEBUG,
650 ACE_TEXT ("Error: --count requires a number")
651 ACE_TEXT (" greater than 0\n")));
652 failed = true;
656 else
658 ACE_DEBUG ((LM_DEBUG,
659 ACE_TEXT ("Unknown option %s\n"),
660 *argv));
661 failed = true;
666 if (failed)
668 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n%s options:\n")
669 ACE_TEXT (" --nsior {Display the naming service IOR and exit}\n")
670 ACE_TEXT ("or:\n")
671 ACE_TEXT (" --ns <ior> {Defaults to standard NameService}\n")
672 ACE_TEXT (" --ior {Display ior for end points}\n")
673 ACE_TEXT (" --ctxior {Display ior for naming contexts}\n")
674 ACE_TEXT (" --tree \"xx\" {Defaults to | for drawing tramlines}\n")
675 ACE_TEXT (" --node \"xx\" {Defaults to + for drawing nodes}\n")
676 ACE_TEXT (" --noloops {Inhibit drawing of naming context loops}\n")
677 ACE_TEXT (" --name <name> {Lists sub-set, defaults to root}\n")
678 ACE_TEXT (" --ctxsep <character> {<name> Context separation character, default /}\n")
679 ACE_TEXT (" --kindsep <character> {<name> ID/Kind separation character, default .}\n")
680 ACE_TEXT (" --max <number> {If given, limits displayed sub-context depth}\n")
681 ACE_TEXT (" --rtt <seconds> {If given, sets the relative round trip timeout policy}\n")
682 ACE_TEXT (" --count <number> {If given, sets the maximum ")
683 ACE_TEXT ("number of entries per request from the NameService}\n"),
684 pname));
685 orb->destroy ();
686 return 1;
689 // Initialise the lengths of the myTree and myNode draw strings.
690 sizeMyTree= ACE_OS::strlen (myTree);
691 sizeMyNode= ACE_OS::strlen (myNode);
693 // Contact the name service
694 CORBA::Object_var obj;
695 if (nameService)
696 obj = orb->string_to_object (nameService);
697 else
698 obj = orb->resolve_initial_references ("NameService");
700 obj = set_rtt(obj.in ());
702 CosNaming::NamingContext_var root_nc =
703 CosNaming::NamingContext::_narrow (obj.in ());
704 if (CORBA::is_nil (root_nc.in ()))
706 ACE_DEBUG ((LM_DEBUG,
707 "Error: nil root naming context\n"));
708 orb->destroy ();
709 return 1;
711 if (name)
713 // Assemble the name from the user string given
714 CosNaming::Name the_name (0);
715 ACE_TCHAR *cp;
716 while (0 != (cp = ACE_OS::strtok (name, ctxsep)))
718 const int index= the_name.length();
719 the_name.length (index+1);
720 ACE_TCHAR *kind = const_cast<ACE_TCHAR*> (ACE_OS::strchr (cp, kindsep));
721 if (kind)
723 *kind = '\0';
724 the_name[index].kind= CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR(++kind));
726 the_name[index].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR(cp));
727 name = 0; // way strtok works
730 // Now find this sub-context and replace the root with it.
731 obj = root_nc->resolve( the_name );
732 root_nc =
733 CosNaming::NamingContext::_narrow (obj.in ());
734 if (CORBA::is_nil (root_nc.in ()))
736 ACE_DEBUG ((LM_DEBUG,
737 "Error: Can't find naming context\n %s\n", name));
738 orb->destroy ();
739 return 1;
743 CORBA::String_var str =
744 orb->object_to_string (root_nc.in ());
746 if (showNSonly)
748 ACE_DEBUG ((LM_DEBUG,
749 "The NameService is located via:\n%C\n", str.in ()));
751 else
753 ACE_DEBUG ((LM_DEBUG,
754 "Naming Service: %C\n---------------\n",
755 ((showCtxIOR)? str.in () : "")));
756 list_context (root_nc.in (), 1, max_count);
759 catch (const CORBA::Exception& ex)
761 ex._tao_print_exception ("Exception in nslist");
762 ++err;
767 orb->destroy ();
769 catch (const CORBA::Exception& ex)
771 ACE_DEBUG ((LM_DEBUG, "\nError:\n"));
772 ex._tao_print_exception ("Exception in while shutting down");
773 ++err;
776 return err;