Parser.cpp
Go to the documentation of this file.
1// **********************************************************************
2//
3// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
4//
5// This copy of Ice is licensed to you under the terms described in the
6// ICE_LICENSE file included in this distribution.
7//
8// **********************************************************************
9
10#include <algorithm>
11
12#include <Ice/ConsoleUtil.h>
13#include <Ice/Ice.h>
15#include <IceStorm/Parser.h>
16#include <IceUtil/DisableWarnings.h>
17
18#ifdef HAVE_READLINE
19#include <readline/history.h>
20#include <readline/readline.h>
21#endif
22
23extern FILE* yyin;
24extern int yydebug;
25
26using namespace std;
27using namespace Ice;
28using namespace IceInternal;
29using namespace IceStorm;
30
31namespace IceStorm
32{
33
35
36#ifdef _WIN32
37 Ice::StringConverterPtr windowsConsoleConverter = 0;
38#endif
39
40} // namespace IceStorm
41
42namespace
43{
44
45 class UnknownManagerException : public Exception
46 {
47 public:
48 UnknownManagerException(const string& name, const char* file, int line) :
49 Exception(file, line), name(name)
50 {
51 }
52
53#ifndef ICE_CPP11_COMPILER
54 virtual ~UnknownManagerException() throw()
55 {
56 }
57#endif
58
59 virtual string
60 ice_id() const
61 {
62 return "::UnknownManagerException";
63 }
64
65 virtual Exception*
66 ice_clone() const
67 {
68 return new UnknownManagerException(*this);
69 }
70
71 virtual void
72 ice_throw() const
73 {
74 throw *this;
75 }
76
77 const string name;
78 };
79
80} // namespace
81
84 const TopicManagerPrx& admin,
85 const map<Ice::Identity, TopicManagerPrx>& managers)
86{
87 return new Parser(communicator, admin, managers);
88}
89
90void
92{
93 consoleOut
94 << "help Print this message.\n"
95 "exit, quit Exit this program.\n"
96 "create TOPICS Add TOPICS.\n"
97 "destroy TOPICS Remove TOPICS.\n"
98 "link FROM TO [COST] Link FROM to TO with the optional given COST.\n"
99 "unlink FROM TO Unlink TO from FROM.\n"
100 "links [INSTANCE-NAME] Display all links for the topics in the current topic\n"
101 " manager, or in the given INSTANCE-NAME.\n"
102 "topics [INSTANCE-NAME] Display the names of all topics in the current topic\n"
103 " manager, or in the given INSTANCE-NAME.\n"
104 "current [INSTANCE-NAME] Display the current topic manager, or change it to\n"
105 " INSTANCE-NAME.\n"
106 "replica [INSTANCE-NAME] Display replication information for the given INSTANCE-NAME.\n"
107 "subscribers TOPICS List TOPICS subscribers.\n";
108}
109
110void
111Parser::create(const list<string>& args)
112{
113 if (args.empty())
114 {
115 error("`create' requires at least one argument (type `help' for more info)");
116 return;
117 }
118
119 for (list<string>::const_iterator i = args.begin(); i != args.end(); ++i)
120 {
121 try
122 {
123 string topicName;
124 TopicManagerPrx manager = findManagerById(*i, topicName);
125 manager->create(topicName);
126 }
127 catch (const Ice::Exception& ex)
128 {
129 exception(
130 ex,
131 args.size() >
132 1); // Print a warning if we're creating multiple topics, an error otherwise.
133 }
134 }
135}
136
137void
138Parser::destroy(const list<string>& args)
139{
140 if (args.empty())
141 {
142 error("`destroy' requires at least one argument (type `help' for more info)");
143 return;
144 }
145
146 for (list<string>::const_iterator i = args.begin(); i != args.end(); ++i)
147 {
148 try
149 {
150 findTopic(*i)->destroy();
151 }
152 catch (const Ice::Exception& ex)
153 {
154 exception(
155 ex,
156 args.size() >
157 1); // Print a warning if we're destroying multiple topics, an error otherwise.
158 }
159 }
160}
161
162void
163Parser::link(const list<string>& args)
164{
165 if (args.size() != 2 && args.size() != 3)
166 {
167 error("`link' requires two or three arguments (type `help' for more info)");
168 return;
169 }
170
171 try
172 {
173 list<string>::const_iterator p = args.begin();
174
175 TopicPrx fromTopic = findTopic(*p++);
176 TopicPrx toTopic = findTopic(*p++);
177 Ice::Int cost = p != args.end() ? atoi(p->c_str()) : 0;
178
179 fromTopic->link(toTopic, cost);
180 }
181 catch (const Exception& ex)
182 {
183 exception(ex);
184 }
185}
186
187void
188Parser::unlink(const list<string>& args)
189{
190 if (args.size() != 2)
191 {
192 error("`unlink' requires exactly two arguments (type `help' for more info)");
193 return;
194 }
195
196 try
197 {
198 list<string>::const_iterator p = args.begin();
199
200 TopicPrx fromTopic = findTopic(*p++);
201 TopicPrx toTopic = findTopic(*p++);
202
203 fromTopic->unlink(toTopic);
204 }
205 catch (const Exception& ex)
206 {
207 exception(ex);
208 }
209}
210
211void
212Parser::links(const list<string>& args)
213{
214 if (args.size() > 1)
215 {
216 error("`links' requires at most one argument (type `help' for more info)");
217 return;
218 }
219
220 try
221 {
222 TopicManagerPrx manager;
223 if (args.size() == 0)
224 {
225 manager = _defaultManager;
226 }
227 else
228 {
229 manager = findManagerByCategory(args.front());
230 }
231
232 TopicDict d = manager->retrieveAll();
233 for (TopicDict::iterator i = d.begin(); i != d.end(); ++i)
234 {
235 LinkInfoSeq links = i->second->getLinkInfoSeq();
236 for (LinkInfoSeq::const_iterator p = links.begin(); p != links.end(); ++p)
237 {
238 consoleOut << i->first << " to " << p->name << " with cost " << p->cost << endl;
239 }
240 }
241 }
242 catch (const Exception& ex)
243 {
244 exception(ex);
245 }
246}
247
248void
249Parser::topics(const list<string>& args)
250{
251 if (args.size() > 1)
252 {
253 error("`topics' requires at most one argument (type `help' for more info)");
254 return;
255 }
256
257 try
258 {
259 TopicManagerPrx manager;
260 if (args.size() == 0)
261 {
262 manager = _defaultManager;
263 }
264 else
265 {
266 manager = findManagerByCategory(args.front());
267 }
268
269 TopicDict d = manager->retrieveAll();
270 for (TopicDict::iterator i = d.begin(); i != d.end(); ++i)
271 {
272 consoleOut << i->first << endl;
273 }
274 }
275 catch (const Exception& ex)
276 {
277 exception(ex);
278 }
279}
280
281void
282Parser::replica(const list<string>& args)
283{
284 if (args.size() > 1)
285 {
286 error("`replica' requires at most one argument (type `help' for more info)");
287 return;
288 }
289
290 try
291 {
293 if (args.size() == 0)
294 {
295 m = _defaultManager;
296 }
297 else
298 {
299 m = findManagerByCategory(args.front());
300 }
301 TopicManagerInternalPrx manager = TopicManagerInternalPrx::uncheckedCast(m);
302 IceStormElection::NodePrx node = manager->getReplicaNode();
303 if (!node)
304 {
305 error("This topic is not replicated");
306 }
307 IceStormElection::NodeInfoSeq nodes = node->nodes();
308 consoleOut << "replica count: " << nodes.size() << endl;
309 for (IceStormElection::NodeInfoSeq::const_iterator p = nodes.begin(); p != nodes.end(); ++p)
310 {
311 try
312 {
313 IceStormElection::QueryInfo info = p->n->query();
314 consoleOut << p->id << ": id: " << info.id << endl;
315 consoleOut << p->id << ": coord: " << info.coord << endl;
316 consoleOut << p->id << ": group name: " << info.group << endl;
317 consoleOut << p->id << ": state: ";
318 switch (info.state)
319 {
321 consoleOut << "inactive";
322 break;
324 consoleOut << "election";
325 break;
327 consoleOut << "reorganization";
328 break;
330 consoleOut << "normal";
331 break;
332 default:
333 consoleOut << "unknown";
334 }
335 consoleOut << endl;
336 consoleOut << p->id << ": group: ";
337 for (IceStormElection::GroupInfoSeq::const_iterator q = info.up.begin();
338 q != info.up.end();
339 ++q)
340 {
341 if (q != info.up.begin())
342 {
343 consoleOut << ",";
344 }
345 consoleOut << q->id;
346 }
347 consoleOut << endl;
348 consoleOut << p->id << ": max: " << info.max << endl;
349 }
350 catch (const Exception& ex)
351 {
352 consoleOut << p->id << ": " << ex.ice_id() << endl;
353 }
354 }
355 }
356 catch (const Exception& ex)
357 {
358 exception(ex);
359 }
360}
361
362void
363Parser::subscribers(const list<string>& args)
364{
365 if (args.empty())
366 {
367 error("subscribers' requires at least one argument (type `help' for more info) ");
368 return;
369 }
370 try
371 {
372 for (list<string>::const_iterator i = args.begin(); i != args.end(); ++i)
373 {
374 TopicPrx topic = _defaultManager->retrieve(*i);
375 consoleOut << (*i) << ": subscribers:" << endl;
376 IdentitySeq subscribers = topic->getSubscribers();
377 for (IdentitySeq::const_iterator j = subscribers.begin(); j != subscribers.end(); ++j)
378 {
379 consoleOut << "\t" << _communicator->identityToString(*j) << endl;
380 }
381 }
382 }
383 catch (const Exception& ex)
384 {
385 exception(ex);
386 }
387}
388
389void
390Parser::current(const list<string>& args)
391{
392 if (args.empty())
393 {
394 consoleOut << _communicator->identityToString(_defaultManager->ice_getIdentity()) << endl;
395 return;
396 }
397 else if (args.size() > 1)
398 {
399 error("`current' requires at most one argument (type `help' for more info)");
400 return;
401 }
402
403 try
404 {
405 TopicManagerPrx manager = findManagerByCategory(args.front());
406 manager->ice_ping();
407 _defaultManager = manager;
408 }
409 catch (const Exception& ex)
410 {
411 exception(ex);
412 }
413}
414
415void
417{
418 consoleOut << "Ice " << ICE_STRING_VERSION << " Copyright (c) 2003-2017 ZeroC, Inc." << endl;
419}
420
421//
422// With older flex version <= 2.5.35 YY_INPUT second
423// paramenter is of type int&, in newer versions it
424// changes to size_t&
425//
426void
427Parser::getInput(char* buf, int& result, size_t maxSize)
428{
429 size_t r = static_cast<size_t>(result);
430 getInput(buf, r, maxSize);
431 result = static_cast<int>(r);
432}
433
434void
435Parser::getInput(char* buf, size_t& result, size_t maxSize)
436{
437 if (!_commands.empty())
438 {
439 if (_commands == ";")
440 {
441 result = 0;
442 }
443 else
444 {
445 result = min(maxSize, _commands.length());
446 strncpy(buf, _commands.c_str(), result);
447 _commands.erase(0, result);
448 if (_commands.empty())
449 {
450 _commands = ";";
451 }
452 }
453 }
454 else
455 {
456#ifdef HAVE_READLINE
457
458 const char* prompt = parser->getPrompt();
459 char* line = readline(const_cast<char*>(prompt));
460 if (!line)
461 {
462 result = 0;
463 }
464 else
465 {
466 if (*line)
467 {
468 add_history(line);
469 }
470
471 result = strlen(line) + 1;
472 if (result > maxSize)
473 {
474 free(line);
475 error("input line too long");
476 result = 0;
477 }
478 else
479 {
480 strcpy(buf, line);
481 strcat(buf, "\n");
482 free(line);
483 }
484 }
485
486#else
487
488 consoleOut << parser->getPrompt() << flush;
489
490 string line;
491 while (true)
492 {
493 char c = static_cast<char>(getc(yyin));
494 if (c == static_cast<char>(EOF))
495 {
496 if (line.size())
497 {
498 line += '\n';
499 }
500 break;
501 }
502
503 line += c;
504 if (c == '\n')
505 {
506 break;
507 }
508 }
509#ifdef _WIN32
510 if (windowsConsoleConverter)
511 {
512 line = nativeToUTF8(line, windowsConsoleConverter);
513 }
514#endif
515 result = line.length();
516 if (result > maxSize)
517 {
518 error("input line too long");
519 buf[0] = EOF;
520 result = 1;
521 }
522 else
523 {
524 strcpy(buf, line.c_str());
525 }
526
527#endif
528 }
529}
530
531void
533{
534 _continue = true;
535}
536
537const char*
539{
540 assert(_commands.empty());
541
542 if (_continue)
543 {
544 _continue = false;
545 return "(cont) ";
546 }
547 else
548 {
549 return ">>> ";
550 }
551}
552
553void
554Parser::error(const char* s)
555{
556 consoleErr << "error: " << s << endl;
557 _errors++;
558}
559
560void
561Parser::error(const string& s)
562{
563 error(s.c_str());
564}
565
566void
567Parser::warning(const char* s)
568{
569 consoleErr << "warning: " << s << endl;
570}
571
572void
573Parser::warning(const string& s)
574{
575 warning(s.c_str());
576}
577
578void
580{
581 consoleErr << s << endl;
582}
583
584int
585Parser::parse(FILE* file, bool debug)
586{
587 yydebug = debug ? 1 : 0;
588
589 assert(!parser);
590 parser = this;
591
592 _errors = 0;
593 bool commands_empty = _commands.empty();
594 (void)commands_empty;
595 yyin = file;
596 assert(yyin);
597
598 _continue = false;
599
600 int status = yyparse();
601 if (_errors)
602 {
603 status = EXIT_FAILURE;
604 }
605
606 parser = 0;
607 return status;
608}
609
610int
611Parser::parse(const std::string& commands, bool debug)
612{
613 yydebug = debug ? 1 : 0;
614
615 assert(!parser);
616 parser = this;
617
618 _errors = 0;
619 _commands = commands;
620 assert(!_commands.empty());
621 yyin = 0;
622
623 _continue = false;
624
625 int status = yyparse();
626 if (_errors)
627 {
628 status = EXIT_FAILURE;
629 }
630
631 parser = 0;
632 return status;
633}
634
636Parser::findManagerById(const string& full, string& arg) const
637{
638 Ice::Identity id = Ice::stringToIdentity(full);
639 arg = id.name;
640 if (id.category.empty())
641 {
642 return _defaultManager;
643 }
644 id.name = "TopicManager";
645 map<Ice::Identity, TopicManagerPrx>::const_iterator p = _managers.find(id);
646 if (p == _managers.end())
647 {
648 throw UnknownManagerException(id.category, __FILE__, __LINE__);
649 }
650 return p->second;
651}
652
654Parser::findManagerByCategory(const string& full) const
655{
656 Ice::Identity id;
657 id.category = full;
658 id.name = "TopicManager";
659 map<Ice::Identity, TopicManagerPrx>::const_iterator p = _managers.find(id);
660 if (p == _managers.end())
661 {
662 throw UnknownManagerException(id.category, __FILE__, __LINE__);
663 }
664 return p->second;
665}
666
668Parser::findTopic(const string& full) const
669{
670 string topicName;
671 TopicManagerPrx manager = findManagerById(full, topicName);
672 return manager->retrieve(topicName);
673}
674
675Parser::Parser(const CommunicatorPtr& communicator,
676 const TopicManagerPrx& admin,
677 const map<Ice::Identity, TopicManagerPrx>& managers) :
678 _communicator(communicator), _defaultManager(admin), _managers(managers)
679{
680#ifdef _WIN32
681 if (!windowsConsoleConverter)
682 {
683 windowsConsoleConverter = Ice::createWindowsStringConverter(GetConsoleOutputCP());
684 }
685#endif
686}
687
688void
689Parser::exception(const Ice::Exception& ex, bool warn)
690{
691 ostringstream os;
692 try
693 {
694 ex.ice_throw();
695 }
696 catch (const LinkExists& ex)
697 {
698 os << "link `" << ex.name << "' already exists";
699 }
700 catch (const NoSuchLink& ex)
701 {
702 os << "couldn't find link `" << ex.name << "'";
703 }
704 catch (const TopicExists& ex)
705 {
706 os << "topic `" << ex.name << "' exists";
707 }
708 catch (const NoSuchTopic& ex)
709 {
710 os << "couldn't find topic `" << ex.name << "'";
711 }
712 catch (const UnknownManagerException& ex)
713 {
714 os << "couldn't find IceStorm service `" << ex.name << "'";
715 }
716 catch (const IdentityParseException& ex)
717 {
718 os << "invalid identity `" << ex.str << "'";
719 }
720 catch (const Ice::LocalException& ex)
721 {
722 os << "couldn't reach IceStorm service:\n" << ex;
723 }
724 catch (const Ice::Exception& ex)
725 {
726 os << ex;
727 }
728
729 if (warn)
730 {
731 warning(os.str());
732 }
733 else
734 {
735 error(os.str());
736 }
737}
int yydebug
Definition Grammar.cpp:755
int yyparse()
Definition Grammar.cpp:1086
FILE * yyin
Definition Scanner.cpp:338
constexpr T c
void replica(const std::list< std::string > &)
Definition Parser.cpp:282
const char * getPrompt()
Definition Parser.cpp:538
void create(const std::list< std::string > &)
Definition Parser.cpp:111
void destroy(const std::list< std::string > &)
Definition Parser.cpp:138
void unlink(const std::list< std::string > &)
Definition Parser.cpp:188
void subscribers(const std::list< std::string > &)
Definition Parser.cpp:363
void continueLine()
Definition Parser.cpp:532
void warning(const char *)
Definition Parser.cpp:567
void current(const std::list< std::string > &)
Definition Parser.cpp:390
void error(const char *)
Definition Parser.cpp:554
void links(const std::list< std::string > &)
Definition Parser.cpp:212
void invalidCommand(const std::string &)
Definition Parser.cpp:579
void showBanner()
Definition Parser.cpp:416
void getInput(char *, int &, size_t)
Definition Parser.cpp:427
void topics(const std::list< std::string > &)
Definition Parser.cpp:249
void link(const std::list< std::string > &)
Definition Parser.cpp:163
static ParserPtr createParser(const Ice::CommunicatorPtr &, const TopicManagerPrx &, const std::map< Ice::Identity, TopicManagerPrx > &)
Definition Parser.cpp:83
int parse(FILE *, bool)
Definition Parser.cpp:585
T min(T t1, T t2)
Definition gdiam.h:44
#define q
This file is part of ArmarX.
::IceInternal::ProxyHandle<::IceProxy::IceStormElection::Node > NodePrx
Definition Election.h:1210
@ NodeStateElection
The node is electing a leader.
Definition Election.ice:142
@ NodeStateNormal
The replica group is active & replicating.
Definition Election.ice:146
@ NodeStateInactive
The node is inactive and awaiting an election.
Definition Election.ice:140
@ NodeStateReorganization
The replica group is reorganizing.
Definition Election.ice:144
::std::vector<::IceStormElection::NodeInfo > NodeInfoSeq
A sequence of node info.
Definition Election.h:1264
::IceInternal::ProxyHandle<::IceProxy::IceStorm::TopicManagerInternal > TopicManagerInternalPrx
::IceInternal::ProxyHandle<::IceProxy::IceStorm::Topic > TopicPrx
Definition IceManager.h:70
::IceUtil::Handle< Parser > ParserPtr
Definition Parser.h:53
Parser * parser
Definition Parser.cpp:34
::IceInternal::ProxyHandle<::IceProxy::IceStorm::TopicManager > TopicManagerPrx
Definition IceManager.h:69
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49
NodeState state
The node state.
Definition Election.ice:192
string group
The nodes group name.
Definition Election.ice:186
GroupInfoSeq up
The sequence of nodes in this nodes group.
Definition Election.ice:195
int coord
The nodes coordinator.
Definition Election.ice:183
int max
The highest priority node that this node has seen.
Definition Election.ice:198