summaryrefslogtreecommitdiff
path: root/cpp/src/IceStorm/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceStorm/Parser.cpp')
-rw-r--r--cpp/src/IceStorm/Parser.cpp732
1 files changed, 732 insertions, 0 deletions
diff --git a/cpp/src/IceStorm/Parser.cpp b/cpp/src/IceStorm/Parser.cpp
new file mode 100644
index 00000000000..a30c369c402
--- /dev/null
+++ b/cpp/src/IceStorm/Parser.cpp
@@ -0,0 +1,732 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/DisableWarnings.h>
+#include <Ice/Ice.h>
+#include <Ice/ConsoleUtil.h>
+#include <IceStorm/Parser.h>
+#include <IceStorm/IceStormInternal.h>
+#include <algorithm>
+
+#ifdef HAVE_READLINE
+# include <readline/readline.h>
+# include <readline/history.h>
+#endif
+
+extern FILE* yyin;
+extern int yydebug;
+
+using namespace std;
+using namespace Ice;
+using namespace IceInternal;
+using namespace IceStorm;
+
+namespace IceStorm
+{
+
+Parser* parser;
+
+#ifdef _WIN32
+Ice::StringConverterPtr windowsConsoleConverter = 0;
+#endif
+
+}
+
+namespace
+{
+
+class UnknownManagerException : public Exception
+{
+public:
+
+ UnknownManagerException(const string& name, const char* file, int line) :
+ Exception(file, line),
+ name(name)
+ {
+ }
+
+#ifndef ICE_CPP11_COMPILER
+ virtual
+ ~UnknownManagerException() throw()
+ {
+ }
+#endif
+
+ virtual string
+ ice_id() const
+ {
+ return "::UnknownManagerException";
+ }
+
+ virtual Exception*
+ ice_clone() const
+ {
+ return new UnknownManagerException(*this);
+ }
+
+ virtual void
+ ice_throw() const
+ {
+ throw *this;
+ }
+
+ const string name;
+};
+
+}
+
+ParserPtr
+Parser::createParser(const CommunicatorPtr& communicator, const TopicManagerPrx& admin,
+ const map<Ice::Identity, TopicManagerPrx>& managers)
+{
+ return new Parser(communicator, admin, managers);
+}
+
+void
+Parser::usage()
+{
+ consoleOut <<
+ "help Print this message.\n"
+ "exit, quit Exit this program.\n"
+ "create TOPICS Add TOPICS.\n"
+ "destroy TOPICS Remove TOPICS.\n"
+ "link FROM TO [COST] Link FROM to TO with the optional given COST.\n"
+ "unlink FROM TO Unlink TO from FROM.\n"
+ "links [INSTANCE-NAME] Display all links for the topics in the current topic\n"
+ " manager, or in the given INSTANCE-NAME.\n"
+ "topics [INSTANCE-NAME] Display the names of all topics in the current topic\n"
+ " manager, or in the given INSTANCE-NAME.\n"
+ "current [INSTANCE-NAME] Display the current topic manager, or change it to\n"
+ " INSTANCE-NAME.\n"
+ "replica [INSTANCE-NAME] Display replication information for the given INSTANCE-NAME.\n"
+ "subscribers TOPICS List TOPICS subscribers.\n"
+ ;
+}
+
+void
+Parser::create(const list<string>& args)
+{
+ if(args.empty())
+ {
+ error("`create' requires at least one argument (type `help' for more info)");
+ return;
+ }
+
+ for(list<string>::const_iterator i = args.begin(); i != args.end() ; ++i)
+ {
+ try
+ {
+ string topicName;
+ TopicManagerPrx manager = findManagerById(*i, topicName);
+ manager->create(topicName);
+ }
+ catch(const Ice::Exception& ex)
+ {
+ exception(ex, args.size() > 1); // Print a warning if we're creating multiple topics, an error otherwise.
+ }
+ }
+}
+
+void
+Parser::destroy(const list<string>& args)
+{
+ if(args.empty())
+ {
+ error("`destroy' requires at least one argument (type `help' for more info)");
+ return;
+ }
+
+ for(list<string>::const_iterator i = args.begin(); i != args.end() ; ++i)
+ {
+ try
+ {
+ findTopic(*i)->destroy();
+ }
+ catch(const Ice::Exception& ex)
+ {
+ exception(ex, args.size() > 1); // Print a warning if we're destroying multiple topics, an error otherwise.
+ }
+ }
+}
+
+void
+Parser::link(const list<string>& args)
+{
+ if(args.size() != 2 && args.size() != 3)
+ {
+ error("`link' requires two or three arguments (type `help' for more info)");
+ return;
+ }
+
+ try
+ {
+ list<string>::const_iterator p = args.begin();
+
+ TopicPrx fromTopic = findTopic(*p++);
+ TopicPrx toTopic = findTopic(*p++);
+ Ice::Int cost = p != args.end() ? atoi(p->c_str()) : 0;
+
+ fromTopic->link(toTopic, cost);
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::unlink(const list<string>& args)
+{
+ if(args.size() != 2)
+ {
+ error("`unlink' requires exactly two arguments (type `help' for more info)");
+ return;
+ }
+
+ try
+ {
+ list<string>::const_iterator p = args.begin();
+
+ TopicPrx fromTopic = findTopic(*p++);
+ TopicPrx toTopic = findTopic(*p++);
+
+ fromTopic->unlink(toTopic);
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::links(const list<string>& args)
+{
+ if(args.size() > 1)
+ {
+ error("`links' requires at most one argument (type `help' for more info)");
+ return;
+ }
+
+ try
+ {
+ TopicManagerPrx manager;
+ if(args.size() == 0)
+ {
+ manager = _defaultManager;
+ }
+ else
+ {
+ manager = findManagerByCategory(args.front());
+ }
+
+ TopicDict d = manager->retrieveAll();
+ for(TopicDict::iterator i = d.begin(); i != d.end(); ++i)
+ {
+ LinkInfoSeq links = i->second->getLinkInfoSeq();
+ for(LinkInfoSeq::const_iterator p = links.begin(); p != links.end(); ++p)
+ {
+ consoleOut << i->first << " to " << p->name << " with cost " << p->cost << endl;
+ }
+ }
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::topics(const list<string>& args)
+{
+ if(args.size() > 1)
+ {
+ error("`topics' requires at most one argument (type `help' for more info)");
+ return;
+ }
+
+ try
+ {
+ TopicManagerPrx manager;
+ if(args.size() == 0)
+ {
+ manager = _defaultManager;
+ }
+ else
+ {
+ manager = findManagerByCategory(args.front());
+ }
+
+ TopicDict d = manager->retrieveAll();
+ for(TopicDict::iterator i = d.begin(); i != d.end(); ++i)
+ {
+ consoleOut << i->first << endl;
+ }
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::replica(const list<string>& args)
+{
+ if(args.size() > 1)
+ {
+ error("`replica' requires at most one argument (type `help' for more info)");
+ return;
+ }
+
+ try
+ {
+ TopicManagerPrx m;
+ if(args.size() == 0)
+ {
+ m = _defaultManager;
+ }
+ else
+ {
+ m = findManagerByCategory(args.front());
+ }
+ TopicManagerInternalPrx manager = TopicManagerInternalPrx::uncheckedCast(m);
+ IceStormElection::NodePrx node = manager->getReplicaNode();
+ if(!node)
+ {
+ error("This topic is not replicated");
+ }
+ IceStormElection::NodeInfoSeq nodes = node->nodes();
+ consoleOut << "replica count: " << nodes.size() << endl;
+ for(IceStormElection::NodeInfoSeq::const_iterator p = nodes.begin(); p != nodes.end(); ++p)
+ {
+ try
+ {
+ IceStormElection::QueryInfo info = p->n->query();
+ consoleOut << p->id << ": id: " << info.id << endl;
+ consoleOut << p->id << ": coord: " << info.coord << endl;
+ consoleOut << p->id << ": group name: " << info.group << endl;
+ consoleOut << p->id << ": state: ";
+ switch(info.state)
+ {
+ case IceStormElection::NodeStateInactive:
+ consoleOut << "inactive";
+ break;
+ case IceStormElection::NodeStateElection:
+ consoleOut << "election";
+ break;
+ case IceStormElection::NodeStateReorganization:
+ consoleOut << "reorganization";
+ break;
+ case IceStormElection::NodeStateNormal:
+ consoleOut << "normal";
+ break;
+ default:
+ consoleOut << "unknown";
+ }
+ consoleOut << endl;
+ consoleOut << p->id << ": group: ";
+ for(IceStormElection::GroupInfoSeq::const_iterator q = info.up.begin(); q != info.up.end(); ++q)
+ {
+ if(q != info.up.begin())
+ {
+ consoleOut << ",";
+ }
+ consoleOut << q->id;
+ }
+ consoleOut << endl;
+ consoleOut << p->id << ": max: " << info.max
+ << endl;
+ }
+ catch(const Exception& ex)
+ {
+ consoleOut << p->id << ": " << ex.ice_id() << endl;
+ }
+ }
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::subscribers(const list<string>& args)
+{
+ if(args.empty())
+ {
+ error("subscribers' requires at least one argument (type `help' for more info) ");
+ return;
+ }
+ try
+ {
+ for(list<string>::const_iterator i = args.begin(); i != args.end() ; ++i)
+ {
+ TopicPrx topic = _defaultManager->retrieve(*i);
+ consoleOut << (*i) << ": subscribers:" << endl;
+ IdentitySeq subscribers = topic->getSubscribers();
+ for(IdentitySeq::const_iterator j = subscribers.begin(); j != subscribers.end(); ++j)
+ {
+ consoleOut << "\t" << _communicator->identityToString(*j) << endl;
+ }
+ }
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::current(const list<string>& args)
+{
+ if(args.empty())
+ {
+ consoleOut << _communicator->identityToString(_defaultManager->ice_getIdentity()) << endl;
+ return;
+ }
+ else if(args.size() > 1)
+ {
+ error("`current' requires at most one argument (type `help' for more info)");
+ return;
+ }
+
+ try
+ {
+ TopicManagerPrx manager = findManagerByCategory(args.front());
+ manager->ice_ping();
+ _defaultManager = manager;
+ }
+ catch(const Exception& ex)
+ {
+ exception(ex);
+ }
+}
+
+void
+Parser::showBanner()
+{
+ consoleOut << "Ice " << ICE_STRING_VERSION << " Copyright (c) 2003-2016 ZeroC, Inc." << endl;
+}
+
+//
+// With older flex version <= 2.5.35 YY_INPUT second
+// paramenter is of type int&, in newer versions it
+// changes to size_t&
+//
+void
+Parser::getInput(char* buf, int& result, size_t maxSize)
+{
+ size_t r = static_cast<size_t>(result);
+ getInput(buf, r, maxSize);
+ result = static_cast<int>(r);
+}
+
+void
+Parser::getInput(char* buf, size_t& result, size_t maxSize)
+{
+ if(!_commands.empty())
+ {
+ if(_commands == ";")
+ {
+ result = 0;
+ }
+ else
+ {
+ result = min(maxSize, _commands.length());
+ strncpy(buf, _commands.c_str(), result);
+ _commands.erase(0, result);
+ if(_commands.empty())
+ {
+ _commands = ";";
+ }
+ }
+ }
+ else
+ {
+#ifdef HAVE_READLINE
+
+ const char* prompt = parser->getPrompt();
+ char* line = readline(const_cast<char*>(prompt));
+ if(!line)
+ {
+ result = 0;
+ }
+ else
+ {
+ if(*line)
+ {
+ add_history(line);
+ }
+
+ result = strlen(line) + 1;
+ if(result > maxSize)
+ {
+ free(line);
+ error("input line too long");
+ result = 0;
+ }
+ else
+ {
+ strcpy(buf, line);
+ strcat(buf, "\n");
+ free(line);
+ }
+ }
+
+#else
+
+ consoleOut << parser->getPrompt() << flush;
+
+ string line;
+ while(true)
+ {
+ char c = static_cast<char>(getc(yyin));
+ if(c == EOF)
+ {
+ if(line.size())
+ {
+ line += '\n';
+ }
+ break;
+ }
+
+ line += c;
+ if(c == '\n')
+ {
+ break;
+ }
+ }
+#ifdef _WIN32
+ if(windowsConsoleConverter)
+ {
+ line = nativeToUTF8(line, windowsConsoleConverter);
+ }
+#endif
+ result = line.length();
+ if(result > maxSize)
+ {
+ error("input line too long");
+ buf[0] = EOF;
+ result = 1;
+ }
+ else
+ {
+ strcpy(buf, line.c_str());
+ }
+
+#endif
+ }
+}
+
+void
+Parser::continueLine()
+{
+ _continue = true;
+}
+
+const char*
+Parser::getPrompt()
+{
+ assert(_commands.empty());
+
+ if(_continue)
+ {
+ _continue = false;
+ return "(cont) ";
+ }
+ else
+ {
+ return ">>> ";
+ }
+}
+
+void
+Parser::error(const char* s)
+{
+ consoleErr << "error: " << s << endl;
+ _errors++;
+}
+
+void
+Parser::error(const string& s)
+{
+ error(s.c_str());
+}
+
+void
+Parser::warning(const char* s)
+{
+ consoleErr << "warning: " << s << endl;
+}
+
+void
+Parser::warning(const string& s)
+{
+ warning(s.c_str());
+}
+
+void
+Parser::invalidCommand(const string& s)
+{
+ consoleErr << s << endl;
+}
+
+int
+Parser::parse(FILE* file, bool debug)
+{
+ yydebug = debug ? 1 : 0;
+
+ assert(!parser);
+ parser = this;
+
+ _errors = 0;
+ _commands.empty();
+ yyin = file;
+ assert(yyin);
+
+ _continue = false;
+
+ int status = yyparse();
+ if(_errors)
+ {
+ status = EXIT_FAILURE;
+ }
+
+ parser = 0;
+ return status;
+}
+
+int
+Parser::parse(const std::string& commands, bool debug)
+{
+ yydebug = debug ? 1 : 0;
+
+ assert(!parser);
+ parser = this;
+
+ _errors = 0;
+ _commands = commands;
+ assert(!_commands.empty());
+ yyin = 0;
+
+ _continue = false;
+
+ int status = yyparse();
+ if(_errors)
+ {
+ status = EXIT_FAILURE;
+ }
+
+ parser = 0;
+ return status;
+}
+
+TopicManagerPrx
+Parser::findManagerById(const string& full, string& arg) const
+{
+ Ice::Identity id = Ice::stringToIdentity(full);
+ arg = id.name;
+ if(id.category.empty())
+ {
+ return _defaultManager;
+ }
+ id.name = "TopicManager";
+ map<Ice::Identity, TopicManagerPrx>::const_iterator p = _managers.find(id);
+ if(p == _managers.end())
+ {
+ throw UnknownManagerException(id.category, __FILE__, __LINE__);
+ }
+ return p->second;
+}
+
+TopicManagerPrx
+Parser::findManagerByCategory(const string& full) const
+{
+ Ice::Identity id;
+ id.category = full;
+ id.name = "TopicManager";
+ map<Ice::Identity, TopicManagerPrx>::const_iterator p = _managers.find(id);
+ if(p == _managers.end())
+ {
+ throw UnknownManagerException(id.category, __FILE__, __LINE__);
+ }
+ return p->second;
+}
+
+TopicPrx
+Parser::findTopic(const string& full) const
+{
+ string topicName;
+ TopicManagerPrx manager = findManagerById(full, topicName);
+ return manager->retrieve(topicName);
+}
+
+Parser::Parser(const CommunicatorPtr& communicator, const TopicManagerPrx& admin,
+ const map<Ice::Identity, TopicManagerPrx>& managers) :
+ _communicator(communicator),
+ _defaultManager(admin),
+ _managers(managers)
+{
+#ifdef _WIN32
+ if(!windowsConsoleConverter)
+ {
+ windowsConsoleConverter = Ice::createWindowsStringConverter(GetConsoleOutputCP());
+ }
+#endif
+}
+
+void
+Parser::exception(const Ice::Exception& ex, bool warn)
+{
+ ostringstream os;
+ try
+ {
+ ex.ice_throw();
+ }
+ catch(const LinkExists& ex)
+ {
+ os << "link `" << ex.name << "' already exists";
+ }
+ catch(const NoSuchLink& ex)
+ {
+ os << "couldn't find link `" << ex.name << "'";
+ }
+ catch(const TopicExists& ex)
+ {
+ os << "topic `" << ex.name << "' exists";
+ }
+ catch(const NoSuchTopic& ex)
+ {
+ os << "couldn't find topic `" << ex.name << "'";
+ }
+ catch(const UnknownManagerException& ex)
+ {
+ os << "couldn't find IceStorm service `" << ex.name << "'";
+ }
+ catch(const IdentityParseException& ex)
+ {
+ os << "invalid identity `" << ex.str << "'";
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ os << "couldn't reach IceStorm service:\n" << ex;
+ }
+ catch(const Ice::Exception& ex)
+ {
+ os << ex;
+ }
+
+ if(warn)
+ {
+ warning(os.str());
+ }
+ else
+ {
+ error(os.str());
+ }
+}