diff options
author | Jose <jose@zeroc.com> | 2017-02-14 11:04:21 +0100 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2017-02-14 11:04:21 +0100 |
commit | ba2a844312a075a421ff3e9f4a101e58600a0fe3 (patch) | |
tree | 9c373366db964e3642584f8110562737120c0556 /cpp | |
parent | Replaced several functional classes by java.util.function classes (diff) | |
download | ice-ba2a844312a075a421ff3e9f4a101e58600a0fe3.tar.bz2 ice-ba2a844312a075a421ff3e9f4a101e58600a0fe3.tar.xz ice-ba2a844312a075a421ff3e9f4a101e58600a0fe3.zip |
Fix issues introduce with 3.6 merge
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/src/IceGrid/Parser.cpp | 2964 | ||||
-rw-r--r-- | cpp/src/IceStorm/Parser.cpp | 732 | ||||
-rw-r--r-- | cpp/src/Slice/JavaUtil.cpp | 5045 | ||||
-rw-r--r-- | cpp/src/slice2php/Main.cpp | 1935 | ||||
-rw-r--r-- | cpp/src/slice2py/Slice2Py.rc | 33 | ||||
-rw-r--r-- | cpp/test/Ice/acm/Client.cpp | 48 |
6 files changed, 10757 insertions, 0 deletions
diff --git a/cpp/src/IceGrid/Parser.cpp b/cpp/src/IceGrid/Parser.cpp new file mode 100644 index 00000000000..2a6bac7606d --- /dev/null +++ b/cpp/src/IceGrid/Parser.cpp @@ -0,0 +1,2964 @@ +// ********************************************************************** +// +// 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 <IceUtil/IceUtil.h> +#include <IceUtil/Options.h> +#include <Ice/Ice.h> +#include <IceXML/Parser.h> +#include <IceGrid/Parser.h> +#include <IceGrid/Util.h> +#include <IceGrid/DescriptorParser.h> +#include <IceGrid/DescriptorHelper.h> +#include <IceBox/IceBox.h> + +#ifdef HAVE_READLINE +# include <readline/readline.h> +# include <readline/history.h> +#endif + +#include <iterator> +#include <iomanip> + +extern FILE* yyin; +extern int yydebug; + +using namespace std; +using namespace IceUtil; +using namespace IceUtilInternal; +using namespace Ice; +using namespace IceGrid; + +namespace +{ + +const char* _commandsHelp[][3] = { +{ "application", "add", +"application add [-n | --no-patch] DESC [TARGET ... ] [NAME=VALUE ... ]\n" +" Add application described in DESC. If specified\n" +" the optional targets TARGET will be deployed.\n" +}, +{ "application", "remove", +"application remove NAME Remove application NAME.\n" +}, +{ "application", "describe", +"application describe NAME Describe application NAME.\n" +}, +{ "application", "diff", +"application diff [-s | --servers] DESC [TARGET ... ] [NAME=VALUE ... ]\n" +" Print the differences betwen the application\n" +" described in DESC and the current deployment.\n" +" If -s or --servers is specified, print the\n" +" the list of servers affected by the differences.\n" +}, +{ "application", "update", +"application update [-n | --no-restart] DESC [TARGET ... ] [NAME=VALUE ... ]\n" +" Update the application described in DESC. If -n or\n" +" --no-restart is specified, the update will fail if\n" +" it is necessary to stop some servers.\n" +}, +{ "application", "patch", +"application patch [-f | --force] NAME\n" +" Patch the given application data. If -f or --force is\n" +" specified, the servers depending on the data to patch\n" +" will be stopped if necessary.\n" +}, +{ "application", "list", +"application list List all deployed applications.\n" +}, +{ "server template", "instantiate", +"server template instantiate APPLICATION NODE TEMPLATE [NAME=VALUE ...]\n" +" Instantiate a server template.\n" +}, +{ "server template", "describe", +"server template describe APPLICATION TEMPLATE\n" +" Describe application server template TEMPLATE.\n" +}, +{ "service template", "describe", +"service template describe APPLICATION TEMPLATE\n" +" Describe application service template TEMPLATE.\n" +}, +{ "node", "list", +"node list List all registered nodes.\n" +}, +{ "node", "describe", +"node describe NAME Show information about node NAME.\n" +}, +{ "node", "ping", +"node ping NAME Ping node NAME.\n" +}, +{ "node", "load", +"node load NAME Print the load of the node NAME.\n" +}, +{ "node", "sockets", +"node sockets [NAME] Print the number of CPU sockets of the\n" +" node NAME or all the nodes if NAME is omitted.\n" +}, +{ "node", "show", +"node show [OPTIONS] NAME [log | stderr | stdout]\n" +" Show node NAME Ice log, stderr or stdout.\n" +" Options:\n" +" -f | --follow: Wait for new data to be available\n" +" -t N | --tail N: Print the last N log messages or lines\n" +" -h N | --head N: Print the first N lines (stderr and stdout only)\n" +}, +{ "node", "shutdown", +"node shutdown NAME Shutdown node NAME.\n" +}, +{ "registry", "list", +"registry list List all registered registries.\n" +}, +{ "registry", "describe", +"registry describe NAME Show information about registry NAME.\n" +}, +{ "registry", "ping", +"registry ping NAME Ping registry NAME.\n" +}, +{ "registry", "show", +"registry show [OPTIONS] NAME [log | stderr | stdout ]\n" +" Show registry NAME Ice log, stderr or stdout.\n" +" Options:\n" +" -f | --follow: Wait for new log or data to be available\n" +" -t N | --tail N: Print the last N log messages or lines\n" +" -h N | --head N: Print the first N lines (stderr and stdout only)\n" +}, +{ "registry", "shutdown", +"registry shutdown NAME Shutdown registry NAME.\n" +}, +{ "server", "list", +"server list List all registered servers.\n" +}, +{ "server", "remove", +"server remove ID Remove server ID.\n" +}, +{ "server", "describe", +"server describe ID Describe server ID.\n" +}, +{ "server", "properties", +"server properties ID Get the run-time properties of server ID.\n" +}, +{ "server", "property", +"server property ID NAME Get the run-time property NAME of server ID.\n" +}, +{ "server", "state", +"server state ID Get the state of server ID.\n" +}, +{ "server", "pid", +"server pid ID Get the process id of server ID.\n" +}, +{ "server", "start", +"server start ID Start server ID.\n" +}, +{ "server", "stop", +"server stop ID Stop server ID.\n" +}, +{ "server", "patch", +"server patch ID Patch server ID.\n" +}, +{ "server", "signal", +"server signal ID SIGNAL Send SIGNAL (e.g. SIGTERM or 15) to server ID.\n" +}, +{ "server", "stdout", +"server stdout ID MESSAGE Write MESSAGE on server ID's stdout.\n" +}, +{ "server", "stderr", +"server stderr ID MESSAGE Write MESSAGE on server ID's stderr.\n" +}, +{ "server", "show", +"server show [OPTIONS] ID [log | stderr | stdout | LOGFILE ]\n" +" Show server ID Ice log, stderr, stdout or log file LOGFILE.\n" +" Options:\n" +" -f | --follow: Wait for new data to be available\n" +" -t N | --tail N: Print the last N log messages or lines\n" +" -h N | --head N: Print the first N lines (not available for Ice log)\n" +}, +{ "server", "enable", +"server enable ID Enable server ID.\n" +}, +{ "server", "disable", +"server disable ID Disable server ID (a disabled server can't be\n" +" started on demand or administratively).\n" +}, + +{ "service", "start", +"service start ID NAME Starts service NAME in IceBox server ID.\n" +}, +{ "service", "stop", +"service stop ID NAME Stops service NAME in IceBox server ID.\n" +}, +{ "service", "describe", +"service describe ID NAME Describes service NAME in IceBox server ID.\n" +}, +{ "service", "properties", +"service properties ID NAME\n" +" Get the run-time properties of service NAME in\n" +" IceBox server ID.\n" +}, +{ "service", "property", +"service property ID NAME PROPERTY\n" +" Get the run-time property PROPERTY of service NAME\n" +" from IceBox server ID.\n" +}, +{ "service", "list", +"service list ID List the services in IceBox server ID.\n" +}, + +{ "adapter", "list", +"adapter list List all registered adapters.\n" +}, +{ "adapter", "endpoints", +"adapter endpoints ID Show the endpoints of adapter or replica group ID.\n" +}, +{ "adapter", "remove", +"adapter remove ID Remove adapter or replica group ID.\n" +}, +{ "object", "add", +"object add PROXY [TYPE] Add an object to the object registry,\n" +" optionally specifying its type.\n" +}, +{ "object", "remove", +"object remove IDENTITY Remove an object from the object registry.\n" +}, +{ "object", "find", +"object find TYPE Find all objects with the type TYPE.\n" +}, +{ "object", "describe", +"object describe EXPR Describe all registered objects whose stringified\n" +" identities match the expression EXPR. A trailing\n" +" wildcard is supported in EXPR, for example\n" +" \"object describe Ice*\".\n" +}, +{ "object", "list", +"object list EXPR List all registered objects whose stringified\n" +" identities match the expression EXPR. A trailing\n" +" wildcard is supported in EXPR, for example\n" +" \"object list Ice*\".\n" +}, +{ 0, 0, 0 } +}; + +int loggerCallbackCount = 0; + +#ifdef _WIN32 +Ice::StringConverterPtr windowsConsoleConverter = 0; +#endif + +void outputNewline() +{ + consoleOut << endl; +} + +void flushOutput() +{ + consoleOut << flush; +} + +void outputString(const string& s) +{ + consoleOut << s; +} + +void writeMessage(const string& message, bool indent) +{ + string s = message; + + if(indent) + { + string::size_type idx = 0; + while((idx = s.find("\n", idx)) != string::npos) + { + s.insert(idx + 1, " "); + ++idx; + } + } + + outputString(s); + outputNewline(); + flushOutput(); +} + +void printLogMessage(const string& p, const Ice::LogMessage& logMessage) +{ + string prefix = p; + + if(!prefix.empty()) + { + prefix += ": "; + } + + string timestamp = IceUtil::Time::microSeconds(logMessage.timestamp).toDateTime(); + + switch(logMessage.type) + { + case Ice::PrintMessage: + { + writeMessage(timestamp + " " + logMessage.message, false); + break; + } + case Ice::TraceMessage: + { + string s = "-- " + timestamp + " " + prefix; + if(!logMessage.traceCategory.empty()) + { + s += logMessage.traceCategory + ": "; + } + s += logMessage.message; + writeMessage(s, true); + break; + } + case Ice::WarningMessage: + { + writeMessage("!- " + timestamp + " " + prefix + "warning: " + logMessage.message, true); + break; + } + case Ice::ErrorMessage: + { + writeMessage("!! " + timestamp + " " + prefix + "error: " + logMessage.message, true); + break; + } + default: + { + assert(0); + } + } +} + +class RemoteLoggerI : public Ice::RemoteLogger +{ +public: + + RemoteLoggerI(); + + virtual void init(const string&, const Ice::LogMessageSeq&, const Ice::Current&); + virtual void log(const Ice::LogMessage&, const Ice::Current&); + + void destroy(); + +private: + + IceUtil::Monitor<IceUtil::Mutex> _monitor; + bool _initDone; + bool _destroyed; + string _prefix; +}; + +typedef IceUtil::Handle<RemoteLoggerI> RemoteLoggerIPtr; + +RemoteLoggerI::RemoteLoggerI() : + _initDone(false), + _destroyed(false) +{ +} + +void +RemoteLoggerI::init(const string& prefix, const Ice::LogMessageSeq& logMessages, const Ice::Current&) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_monitor); + if(!_destroyed) + { + _prefix = prefix; + + for(Ice::LogMessageSeq::const_iterator p = logMessages.begin(); p != logMessages.end(); ++p) + { + printLogMessage(_prefix, *p); + } + + _initDone = true; + _monitor.notifyAll(); + } +} + +void +RemoteLoggerI::log(const Ice::LogMessage& logMessage, const Ice::Current&) +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_monitor); + while(!_initDone && !_destroyed) + { + _monitor.wait(); + } + if(!_destroyed) + { + printLogMessage(_prefix, logMessage); + } +} + +void +RemoteLoggerI::destroy() +{ + IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_monitor); + _destroyed = true; + _monitor.notifyAll(); +} + +} + +namespace IceGrid +{ + +Parser* parser; + +} + +ParserPtr +Parser::createParser(const CommunicatorPtr& communicator, const AdminSessionPrx& session, const AdminPrx& admin, + bool interactive) +{ + return new Parser(communicator, session, admin, interactive); +} + +void +Parser::usage(const string& category, const string& command) +{ + if(_helpCommands.find(category) == _helpCommands.end()) + { + invalidCommand("unknown command `" + category + "'"); + } + else if(_helpCommands[category].find(command) == _helpCommands[category].end()) + { + invalidCommand("unknown command `" + category + " " + command + "'"); + } + else + { + consoleOut << _helpCommands[category][command]; + } +} + +void +Parser::usage(const string& category, const list<string>& args) +{ + if(args.empty()) + { + usage(category); + } + else if(args.size() > 1) + { + invalidCommand("`help' requires at most 1 argument"); + } + else + { + usage(category, *args.begin()); + } +} + +void +Parser::usage() +{ + consoleOut << + "help Print this message.\n" + "exit, quit Exit this program.\n" + "CATEGORY help Print the help section of the given CATEGORY.\n" + "COMMAND help Print the help of the given COMMAND.\n" + "\n" + "List of help categories:\n" + "\n" + " application: commands to manage applications\n" + " node: commands to manage nodes\n" + " registry: commands to manage registries\n" + " server: commands to manage servers\n" + " service: commands to manage services\n" + " adapter: commands to manage adapters\n" + " object: commands to manage objects\n" + " server template: commands to manage server templates\n" + " service template: commands to manage service templates\n" + "\n"; +} + +void +Parser::interrupt() +{ + Lock sync(*this); + _interrupted = true; + notifyAll(); +} + +bool +Parser::interrupted() const +{ + Lock sync(*this); + return _interrupted; +} + +void +Parser::resetInterrupt() +{ + Lock sync(*this); + _interrupted = false; +} + +void +Parser::checkInterrupted() +{ + if(!_interactive) + { + Lock sync(*this); + if(_interrupted) + { + throw "interrupted with Ctrl-C"; + } + } +} + +void +Parser::addApplication(const list<string>& origArgs) +{ + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("n", "no-patch"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + + if(args.size() < 1) + { + invalidCommand("application add", "requires at least one argument"); + return; + } + + try + { + StringSeq targets; + map<string, string> vars; + + vector<string>::const_iterator p = args.begin(); + string desc = *p++; + + for(; p != args.end(); ++p) + { + string::size_type pos = p->find('='); + if(pos != string::npos) + { + vars[p->substr(0, pos)] = p->substr(pos + 1); + } + else + { + targets.push_back(*p); + } + } + + // + // Add the application. + // + ApplicationDescriptor app = DescriptorParser::parseDescriptor(desc, targets, vars, _communicator, _admin); + _admin->addApplication(app); + + if(!opts.isSet("no-patch")) + { + // + // Patch the application. + // + try + { + _admin->patchApplication(app.name, true); + } + catch(const PatchException& ex) + { + warning(patchFailed(ex.reasons)); + } + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::removeApplication(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("application remove", "requires exactly one argument"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + + string name = *p++; + + _admin->removeApplication(name); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeApplication(const list<string>& args) +{ + if(args.size() < 1) + { + invalidCommand("application describe", "requires at least one argument"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + + string name = *p++; + ostringstream os; + Output out(os); + ApplicationInfo info = _admin->getApplicationInfo(name); + ApplicationHelper helper(_communicator, info.descriptor); + helper.print(out, info); + out << nl; + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::diffApplication(const list<string>& origArgs) +{ + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("s", "servers"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + + if(args.size() < 1) + { + invalidCommand("application diff" , "requires at least one argument"); + return; + } + + try + { + StringSeq targets; + map<string, string> vars; + + vector<string>::const_iterator p = args.begin(); + string desc = *p++; + + for(; p != args.end(); ++p) + { + string::size_type pos = p->find('='); + if(pos != string::npos) + { + vars[p->substr(0, pos)] = p->substr(pos + 1); + } + else + { + targets.push_back(*p); + } + } + + ApplicationDescriptor newApp = DescriptorParser::parseDescriptor(desc, targets, vars, _communicator, _admin); + ApplicationInfo origApp = _admin->getApplicationInfo(newApp.name); + + ApplicationHelper newAppHelper(_communicator, newApp); + ApplicationHelper oldAppHelper(_communicator, origApp.descriptor); + + ostringstream os; + Output out(os); + if(opts.isSet("servers")) + { + map<string, ServerInfo> oldServers = oldAppHelper.getServerInfos(origApp.uuid, origApp.revision); + map<string, ServerInfo> newServers = newAppHelper.getServerInfos(origApp.uuid, origApp.revision); + + vector<string> messages; + map<string, ServerInfo>::const_iterator p; + for(p = oldServers.begin(); p != oldServers.end(); ++p) + { + map<string, ServerInfo>::const_iterator q = newServers.find(p->first); + if(q == newServers.end()) + { + messages.push_back("server `" + p->first + "': removed"); + } + } + + for(p = newServers.begin(); p != newServers.end(); ++p) + { + map<string, ServerInfo>::const_iterator q = oldServers.find(p->first); + if(q == oldServers.end()) + { + messages.push_back("server `" + p->first + "': added"); + } + else if(isServerUpdated(p->second, q->second)) + { + if(isServerUpdated(p->second, q->second, true)) // Ignore properties + { + messages.push_back("server `" + p->first + "': updated (restart required)"); + } + else + { + messages.push_back("server `" + p->first + "': properties updated (no restart required)"); + } + } + } + + out << "application `" << origApp.descriptor.name << "'"; + out << sb; + sort(messages.begin(), messages.end()); + for(vector<string>::const_iterator r = messages.begin(); r != messages.end(); ++r) + { + out << nl << *r; + } + out << eb; + } + else + { + newAppHelper.printDiff(out, oldAppHelper); + } + out << nl; + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::updateApplication(const list<string>& origArgs) +{ + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("n", "no-restart"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + + if(args.size() < 1) + { + invalidCommand("application update", "requires at least one argument"); + return; + } + + try + { + StringSeq targets; + map<string, string> vars; + + vector<string>::const_iterator p = args.begin(); + string xml = *p++; + + for(; p != args.end(); ++p) + { + string::size_type pos = p->find('='); + if(pos != string::npos) + { + vars[p->substr(0, pos)] = p->substr(pos + 1); + } + else + { + targets.push_back(*p); + } + } + + ApplicationDescriptor desc = DescriptorParser::parseDescriptor(xml, targets, vars, _communicator, _admin); + if(opts.isSet("no-restart")) + { + _admin->syncApplicationWithoutRestart(desc); + } + else + { + _admin->syncApplication(desc); + } + } + catch(const Ice::OperationNotExistException&) + { + error("registry doesn't support updates without restart"); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::patchApplication(const list<string>& origArgs) +{ + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("f", "force"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + + if(args.size() != 1) + { + invalidCommand("application patch", "requires exactly one argument"); + return; + } + + try + { + vector<string>::const_iterator p = args.begin(); + string name = *p++; + _admin->patchApplication(name, opts.isSet("force")); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listAllApplications(const list<string>& args) +{ + if(!args.empty()) + { + invalidCommand("application list", "doesn't require any argument"); + return; + } + + try + { + Ice::StringSeq names = _admin->getAllApplicationNames(); + ostringstream os; + copy(names.begin(), names.end(), ostream_iterator<string>(os,"\n")); + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeServerTemplate(const list<string>& args) +{ + if(args.size() != 2) + { + invalidCommand("server template describe", "requires exactly two arguments"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + + string name = *p++; + string templ = *p++; + + ApplicationInfo application = _admin->getApplicationInfo(name); + + ostringstream os; + Output out(os); + TemplateDescriptorDict::const_iterator q = application.descriptor.serverTemplates.find(templ); + if(q != application.descriptor.serverTemplates.end()) + { + out << "server template `" << templ << "'"; + out << sb; + + out << nl << "parameters = `" << toString(q->second.parameters) << "'"; + out << nl; + + ServerDescriptorPtr server = ServerDescriptorPtr::dynamicCast(q->second.descriptor); + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(server); + if(iceBox) + { + IceBoxHelper(iceBox).print(_communicator, out); + } + else + { + ServerHelper(server).print(_communicator, out); + } + out << eb; + out << nl; + } + else + { + error("no server template with id `" + templ + "'"); + } + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::instantiateServerTemplate(const list<string>& args) +{ + if(args.size() < 3) + { + invalidCommand("server template instantiate", "requires at least three arguments"); + return; + } + + try + { + map<string, string> vars; + + list<string>::const_iterator p = args.begin(); + string application = *p++; + string node = *p++; + string templ = *p++; + for(; p != args.end(); ++p) + { + string::size_type pos = p->find('='); + if(pos != string::npos) + { + vars[p->substr(0, pos)] = p->substr(pos + 1); + } + } + + ServerInstanceDescriptor desc; + desc._cpp_template = templ; + desc.parameterValues = vars; + _admin->instantiateServer(application, node, desc); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeServiceTemplate(const list<string>& args) +{ + if(args.size() != 2) + { + invalidCommand("service template describe", "requires exactly two arguments"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + + string name = *p++; + string templ = *p++; + + ApplicationInfo application = _admin->getApplicationInfo(name); + + ostringstream os; + Output out(os); + TemplateDescriptorDict::const_iterator q = application.descriptor.serviceTemplates.find(templ); + if(q != application.descriptor.serviceTemplates.end()) + { + out << "service template `" << templ << "'"; + out << sb; + + out << nl << "parameters = `" << toString(q->second.parameters) << "'"; + out << nl; + + ServiceDescriptorPtr desc = ServiceDescriptorPtr::dynamicCast(q->second.descriptor); + ServiceHelper(desc).print(_communicator, out); + out << eb; + out << nl; + } + else + { + invalidCommand("no service template with id `" + templ + "'"); + } + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeNode(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("node describe", "requires exactly one argument"); + return; + } + + try + { + NodeInfo info = _admin->getNodeInfo(args.front()); + ostringstream os; + Output out(os); + out << "node `" << args.front() << "'"; + out << sb; + out << nl << "operating system = `" << info.os << "'"; + out << nl << "host name = `" << info.hostname << "'"; + out << nl << "release = `" << info.release << "'"; + out << nl << "version = `" << info.version << "'"; + out << nl << "machine type = `" << info.machine << "'"; + out << nl << "number of threads = `" << info.nProcessors << "'"; + out << eb; + out << nl; + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::pingNode(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("node ping", "requires exactly one argument"); + return; + } + + try + { + if(_admin->pingNode(args.front())) + { + consoleOut << "node is up" << endl; + } + else + { + consoleOut << "node is down" << endl; + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::printLoadNode(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("node load", "requires exactly one argument"); + return; + } + + try + { + LoadInfo load = _admin->getNodeLoad(args.front()); + consoleOut << "load average (1/5/15): " << load.avg1 << " / " << load.avg5 << " / " << load.avg15 << endl; + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::printNodeProcessorSockets(const list<string>& args) +{ + if(args.size() > 1) + { + invalidCommand("node sockets", "requires no more than one argument"); + return; + } + + try + { + if(args.size() == 1) + { + try + { + consoleOut << _admin->getNodeProcessorSocketCount(args.front()) << endl; + } + catch(const Ice::OperationNotExistException&) + { + consoleOut << "not supported" << endl; + } + } + else + { + Ice::StringSeq names = _admin->getAllNodeNames(); + map<string, pair< vector<string>, int> > processorSocketCounts; + for(Ice::StringSeq::const_iterator p = names.begin(); p != names.end(); p++) + { + try + { + NodeInfo info = _admin->getNodeInfo(*p); + processorSocketCounts[info.hostname].first.push_back(*p); + try + { + processorSocketCounts[info.hostname].second = _admin->getNodeProcessorSocketCount(*p); + } + catch(const Ice::OperationNotExistException&) + { + // Not supported. + processorSocketCounts[info.hostname].second = 0; + } + } + catch(const NodeNotExistException&) + { + } + catch(const NodeUnreachableException&) + { + } + } + + ostringstream os; + os.flags(ios::left); + os << setw(20) << "Hostname" << setw(20) << "| # of sockets" << setw(39) << "| Nodes" << endl; + os << setw(79) << "=====================================================================" << endl; + for(map<string, pair< vector<string>, int> >::const_iterator q = processorSocketCounts.begin(); + q != processorSocketCounts.end(); ++q) + { + os << setw(20) << setiosflags(ios::left) <<q->first; + os << "| " << setw(18) << setiosflags(ios::left) << q->second.second; + os << "| " << setw(37) << setiosflags(ios::left) << toString(q->second.first); + os << endl; + } + consoleOut << os.str() << flush; + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::shutdownNode(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("node shutdown", "requires exactly one argument"); + return; + } + + try + { + _admin->shutdownNode(args.front()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listAllNodes(const list<string>& args) +{ + if(!args.empty()) + { + invalidCommand("node list", "doesn't require any argument"); + return; + } + + try + { + ostringstream os; + Ice::StringSeq names = _admin->getAllNodeNames(); + copy(names.begin(), names.end(), ostream_iterator<string>(os,"\n")); + consoleOut << os.str(); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeRegistry(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("registry describe", "requires exactly one argument"); + return; + } + + try + { + RegistryInfo info = _admin->getRegistryInfo(args.front()); + ostringstream os; + Output out(os); + out << "registry `" << args.front() << "'"; + out << sb; + out << nl << "host name = `" << info.hostname << "'"; + out << eb; + out << nl; + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::pingRegistry(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("registry ping", "requires exactly one argument"); + return; + } + + try + { + if(_admin->pingRegistry(args.front())) + { + consoleOut << "registry is up" << endl; + } + else + { + consoleOut << "registry is down" << endl; + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::shutdownRegistry(const list<string>& args) +{ + if(args.size() > 1) + { + invalidCommand("registry shutdown", "requires at most one argument"); + return; + } + + try + { + if(args.empty()) + { + _admin->shutdown(); + } + else + { + _admin->shutdownRegistry(args.front()); + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listAllRegistries(const list<string>& args) +{ + if(!args.empty()) + { + invalidCommand("registry list", "doesn't require any argument"); + return; + } + + try + { + ostringstream os; + Ice::StringSeq names = _admin->getAllRegistryNames(); + copy(names.begin(), names.end(), ostream_iterator<string>(os,"\n")); + consoleOut << os.str(); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::removeServer(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("server remove", "requires exactly one argument"); + return; + } + + try + { + ServerInfo info = _admin->getServerInfo(args.front()); + NodeUpdateDescriptor nodeUpdate; + nodeUpdate.name = info.node; + nodeUpdate.removeServers.push_back(args.front()); + ApplicationUpdateDescriptor update; + update.name = info.application; + update.nodes.push_back(nodeUpdate); + _admin->updateApplication(update); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::startServer(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("server start", "requires exactly one argument"); + return; + } + + try + { + _admin->startServer(args.front()); + } + catch(const ServerStartException& ex) + { + error("the server didn't start successfully:\n" + ex.reason); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::stopServer(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("server stop", "requires exactly one argument"); + return; + } + + try + { + _admin->stopServer(args.front()); + } + catch(const ServerStopException& ex) + { + error("the server didn't stop successfully:\n" + ex.reason); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::patchServer(const list<string>& origArgs) +{ + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("f", "force"); + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + + if(args.size() != 1) + { + invalidCommand("server patch", "requires exactly one argument"); + return; + } + + try + { + _admin->patchServer(args.front(), opts.isSet("force")); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::signalServer(const list<string>& args) +{ + if(args.size() != 2) + { + invalidCommand("server signal", "requires exactly two arguments"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + string server = *p++; + _admin->sendSignal(server, *p); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + + +void +Parser::writeMessage(const list<string>& args, int fd) +{ + if(args.size() != 2) + { + invalidCommand("server stdout or server stderr", "requires exactly two arguments"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + string server = *p++; + + Ice::ObjectPrx serverAdmin = _admin->getServerAdmin(server); + Ice::ProcessPrx process = Ice::ProcessPrx::uncheckedCast(serverAdmin, "Process"); + + process->writeMessage(*p, fd); + } + catch(const Ice::ObjectNotExistException&) + { + error("couldn't reach the server's Admin object"); + } + catch(const Ice::FacetNotExistException&) + { + error("the server's Admin object does not provide a 'Process' facet"); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeServer(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("server describe", "requires exactly one argument"); + return; + } + + try + { + ServerInfo info = _admin->getServerInfo(args.front()); + ostringstream os; + Output out(os); + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(info.descriptor); + if(iceBox) + { + IceBoxHelper(iceBox).print(_communicator, out, info); + } + else + { + ServerHelper(info.descriptor).print(_communicator, out, info); + } + out << nl; + outputString(os.str()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::stateServer(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("server state", "requires exactly one argument"); + return; + } + + try + { + ServerState state = _admin->getServerState(args.front()); + string enabled = _admin->isServerEnabled(args.front()) ? "enabled" : "disabled"; + switch(state) + { + case Inactive: + { + consoleOut << "inactive (" << enabled << ")" << endl; + break; + } + case Activating: + { + consoleOut << "activating (" << enabled << ")" << endl; + break; + } + case Active: + { + int pid = _admin->getServerPid(args.front()); + consoleOut << "active (pid = " << pid << ", " << enabled << ")" << endl; + break; + } + case ActivationTimedOut: + { + int pid = _admin->getServerPid(args.front()); + consoleOut << "activation timed out (pid = " << pid << ", " << enabled << ")" << endl; + break; + } + case Deactivating: + { + consoleOut << "deactivating (" << enabled << ")" << endl; + break; + } + case Destroying: + { + consoleOut << "destroying (" << enabled << ")" << endl; + break; + } + case Destroyed: + { + consoleOut << "destroyed (" << enabled << ")" << endl; + break; + } + default: + assert(false); + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::pidServer(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("server pid", "requires exactly one argument"); + return; + } + + try + { + int pid = _admin->getServerPid(args.front()); + if(pid > 0) + { + consoleOut << pid << endl; + } + else + { + error("server is not running"); + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::propertiesServer(const list<string>& args, bool single) +{ + if(single && args.size() != 2) + { + invalidCommand("server property", "requires exactly two arguments"); + return; + } + else if(!single && args.size() != 1) + { + invalidCommand("server properties", "requires exactly one argument"); + return; + } + + try + { + Ice::ObjectPrx serverAdmin = _admin->getServerAdmin(args.front()); + Ice::PropertiesAdminPrx propAdmin = Ice::PropertiesAdminPrx::uncheckedCast(serverAdmin, "Properties"); + + if(single) + { + string val = propAdmin->getProperty(*(++args.begin())); + consoleOut << val << endl; + } + else + { + Ice::PropertyDict properties = propAdmin->getPropertiesForPrefix(""); + for(Ice::PropertyDict::const_iterator p = properties.begin(); p != properties.end(); ++p) + { + consoleOut << p->first << "=" << p->second << endl; + } + } + } + catch(const Ice::ObjectNotExistException&) + { + error("couldn't reach the server's Admin object"); + } + catch(const Ice::FacetNotExistException&) + { + error("the server's Admin object does not provide a 'Properties' facet"); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::enableServer(const list<string>& args, bool enable) +{ + if(args.size() != 1) + { + if(enable) + { + invalidCommand("server enable", "requires exactly one argument"); + } + else + { + invalidCommand("server disable", "requires exactly one argument"); + } + return; + } + + try + { + _admin->enableServer(args.front(), enable); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listAllServers(const list<string>& args) +{ + if(!args.empty()) + { + invalidCommand("server list", "doesn't require any argument"); + return; + } + + try + { + ostringstream os; + Ice::StringSeq ids = _admin->getAllServerIds(); + copy(ids.begin(), ids.end(), ostream_iterator<string>(os,"\n")); + consoleOut << os.str(); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::startService(const list<string>& args) +{ + if(args.size() != 2) + { + invalidCommand("service start", "requires exactly two arguments"); + return; + } + + string server = args.front(); + string service = *(++args.begin()); + try + { + Ice::ObjectPrx admin = _admin->getServerAdmin(server); + IceBox::ServiceManagerPrx manager = IceBox::ServiceManagerPrx::uncheckedCast(admin, "IceBox.ServiceManager"); + manager->startService(service); + } + catch(const IceBox::AlreadyStartedException&) + { + error("the service `" + service + "' is already started"); + } + catch(const IceBox::NoSuchServiceException&) + { + error("couldn't find service `" + service + "'"); + } + catch(const Ice::ObjectNotExistException&) + { + error("couldn't reach the server's Admin object"); + } + catch(const Ice::FacetNotExistException&) + { + error("the server's Admin object does not provide a 'IceBox.ServiceManager' facet"); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::stopService(const list<string>& args) +{ + if(args.size() != 2) + { + invalidCommand("service stop", "requires exactly two arguments"); + return; + } + + string server = args.front(); + string service = *(++args.begin()); + try + { + Ice::ObjectPrx admin = _admin->getServerAdmin(server); + IceBox::ServiceManagerPrx manager = IceBox::ServiceManagerPrx::uncheckedCast(admin, "IceBox.ServiceManager"); + manager->stopService(service); + } + catch(const IceBox::AlreadyStoppedException&) + { + error("the service `" + service + "' is already stopped"); + } + catch(const IceBox::NoSuchServiceException&) + { + error("couldn't find service `" + service + "'"); + } + catch(const Ice::ObjectNotExistException&) + { + error("couldn't reach the server's Admin object"); + } + catch(const Ice::FacetNotExistException&) + { + error("the server's Admin object does not provide a 'IceBox.ServiceManager' facet"); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeService(const list<string>& args) +{ + if(args.size() != 2) + { + invalidCommand("service describe", "requires exactly two arguments"); + return; + } + + string server = args.front(); + string service = *(++args.begin()); + try + { + ServerInfo info = _admin->getServerInfo(server); + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(info.descriptor); + if(!iceBox) + { + error("server `" + server + "' is not an IceBox server"); + return; + } + + ostringstream os; + Output out(os); + bool found = false; + for(ServiceInstanceDescriptorSeq::const_iterator p = iceBox->services.begin(); p != iceBox->services.end(); ++p) + { + if(p->descriptor && p->descriptor->name == service) + { + ServiceHelper(p->descriptor).print(_communicator, out); + out << nl; + found = true; + break; + } + } + outputString(os.str()); + + if(!found) + { + error("couldn't find service `" + service + "'"); + return; + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::propertiesService(const list<string>& args, bool single) +{ + if(single && args.size() != 3) + { + invalidCommand("service property", "requires exactly three arguments"); + return; + } + else if(!single && args.size() != 2) + { + invalidCommand("service properties", "requires exactly two argument"); + return; + } + + list<string>::const_iterator a = args.begin(); + string server = *a++; + string service = *a++; + string property = single ? *a++ : string(); + + try + { + // + // First, we ensure that the service exists. + // + ServerInfo info = _admin->getServerInfo(server); + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(info.descriptor); + if(!iceBox) + { + error("server `" + server + "' is not an IceBox server"); + return; + } + + bool found = false; + for(ServiceInstanceDescriptorSeq::const_iterator p = iceBox->services.begin(); p != iceBox->services.end(); ++p) + { + if(p->descriptor && p->descriptor->name == service) + { + found = true; + break; + } + } + if(!found) + { + error("couldn't find service `" + service + "'"); + return; + } + + Ice::ObjectPrx admin = _admin->getServerAdmin(server); + Ice::PropertiesAdminPrx propAdmin; + if(getPropertyAsInt(info.descriptor->propertySet.properties, "IceBox.UseSharedCommunicator." + service) > 0) + { + propAdmin = Ice::PropertiesAdminPrx::uncheckedCast(admin, "IceBox.SharedCommunicator.Properties"); + } + else + { + propAdmin = Ice::PropertiesAdminPrx::uncheckedCast(admin, "IceBox.Service." + service + ".Properties"); + } + + if(single) + { + string val = propAdmin->getProperty(property); + consoleOut << val << endl; + } + else + { + Ice::PropertyDict properties = propAdmin->getPropertiesForPrefix(""); + for(Ice::PropertyDict::const_iterator p = properties.begin(); p != properties.end(); ++p) + { + consoleOut << p->first << "=" << p->second << endl; + } + } + } + catch(const Ice::ObjectNotExistException&) + { + error("couldn't reach the server's Admin object"); + } + catch(const Ice::FacetNotExistException&) + { + error("the server's Admin object does not provide an 'IceBox.Service." + service + ".Properties' facet"); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listServices(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("service list", "requires exactly one argument"); + return; + } + + string server = args.front(); + try + { + ServerInfo info = _admin->getServerInfo(server); + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(info.descriptor); + if(!iceBox) + { + error("server `" + server + "' is not an IceBox server"); + return; + } + for(ServiceInstanceDescriptorSeq::const_iterator p = iceBox->services.begin(); p != iceBox->services.end(); ++p) + { + if(p->descriptor) + { + consoleOut << p->descriptor->name << endl; + } + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + + +void +Parser::endpointsAdapter(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("adapter endpoints", "requires exactly one argument"); + return; + } + + try + { + string adapterId = args.front(); + AdapterInfoSeq adpts = _admin->getAdapterInfo(adapterId); + if(adpts.size() == 1 && adpts.begin()->id == adapterId) + { + string endpoints = _communicator->proxyToString(adpts.begin()->proxy); + consoleOut << (endpoints.empty() ? string("<inactive>") : endpoints) << endl; + } + else + { + for(AdapterInfoSeq::const_iterator p = adpts.begin(); p != adpts.end(); ++p) + { + consoleOut << (p->id.empty() ? string("<empty>") : p->id) << ": "; + string endpoints = _communicator->proxyToString(p->proxy); + consoleOut << (endpoints.empty() ? string("<inactive>") : endpoints) << endl; + } + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::removeAdapter(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("adapter remove", "requires exactly one argument"); + return; + } + + try + { + _admin->removeAdapter(*args.begin()); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listAllAdapters(const list<string>& args) +{ + if(!args.empty()) + { + invalidCommand("adapter list", "doesn't require any argument"); + return; + } + + try + { + ostringstream os; + Ice::StringSeq ids = _admin->getAllAdapterIds(); + copy(ids.begin(), ids.end(), ostream_iterator<string>(os,"\n")); + consoleOut << os.str(); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::addObject(const list<string>& args) +{ + if(args.size() != 1 && args.size() != 2) + { + invalidCommand("object add", "requires one or two arguments"); + return; + } + + try + { + list<string>::const_iterator p = args.begin(); + + string proxy = *p++; + + if(p != args.end()) + { + string type = *p++; + _admin->addObjectWithType(_communicator->stringToProxy(proxy), type); + } + else + { + _admin->addObject(_communicator->stringToProxy(proxy)); + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::removeObject(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("object remove", "requires exactly one argument"); + return; + } + + try + { + _admin->removeObject(Ice::stringToIdentity((*(args.begin())))); + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::findObject(const list<string>& args) +{ + if(args.size() != 1) + { + invalidCommand("object find", "requires exactly one argument"); + return; + } + + try + { + ObjectInfoSeq objects = _admin->getObjectInfosByType(*(args.begin())); + for(ObjectInfoSeq::const_iterator p = objects.begin(); p != objects.end(); ++p) + { + consoleOut << _communicator->proxyToString(p->proxy) << endl; + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::describeObject(const list<string>& args) +{ + if(args.size() > 1) + { + invalidCommand("object describe", "requires at most one argument"); + return; + } + + try + { + ObjectInfoSeq objects; + if(args.size() == 1) + { + string arg = *(args.begin()); + if(arg.find('*') == string::npos) + { + ObjectInfo info = _admin->getObjectInfo(Ice::stringToIdentity(arg)); + consoleOut << "proxy = `" << _communicator->proxyToString(info.proxy) << "'" << endl; + consoleOut << "type = `" << info.type << "'" << endl; + return; + } + else + { + objects = _admin->getAllObjectInfos(arg); + } + } + else + { + objects = _admin->getAllObjectInfos(""); + } + + for(ObjectInfoSeq::const_iterator p = objects.begin(); p != objects.end(); ++p) + { + consoleOut << "proxy = `" << _communicator->proxyToString(p->proxy) << "' type = `" << p->type << "'" << endl; + } + + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::listObject(const list<string>& args) +{ + if(args.size() > 1) + { + invalidCommand("object list", "requires at most one argument"); + return; + } + + try + { + ObjectInfoSeq objects; + if(args.size() == 1) + { + objects = _admin->getAllObjectInfos(*(args.begin())); + } + else + { + objects = _admin->getAllObjectInfos(""); + } + + for(ObjectInfoSeq::const_iterator p = objects.begin(); p != objects.end(); ++p) + { + consoleOut << _communicator->identityToString(p->proxy->ice_getIdentity()) << endl; + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::show(const string& reader, const list<string>& origArgs) +{ + list<string> copyArgs = origArgs; + copyArgs.push_front("icegridadmin"); + + IceUtilInternal::Options opts; + opts.addOpt("f", "follow"); + opts.addOpt("h", "head", IceUtilInternal::Options::NeedArg); + opts.addOpt("t", "tail", IceUtilInternal::Options::NeedArg); + + vector<string> args; + try + { + for(list<string>::const_iterator p = copyArgs.begin(); p != copyArgs.end(); ++p) + { + args.push_back(*p); + } + args = opts.parse(args); + } + catch(const IceUtilInternal::BadOptException& e) + { + error(e.reason); + return; + } + + if(args.size() != 2) + { + invalidCommand(reader + " show", "requires two arguments"); + return; + } + + try + { + vector<string>::const_iterator p = args.begin(); + string id = *p++; + string filename = *p++; + + consoleOut << reader << " `" << id << "' " << filename << ": " << flush; + Ice::StringSeq lines; + + bool head = opts.isSet("head"); + bool tail = opts.isSet("tail"); + if(head && tail) + { + invalidCommand("can't specify both -h | --head and -t | --tail options"); + return; + } + if(head && reader == "log") + { + invalidCommand("can't specify -h | --head option with log"); + return; + } + + int lineCount = 20; + if(head || tail) + { + if(head) + { + istringstream is(opts.optArg("head")); + is >> lineCount; + } + else + { + istringstream is(opts.optArg("tail")); + is >> lineCount; + } + if(lineCount <= 0) + { + invalidCommand("invalid argument for -h | --head or -t | --tail option"); + return; + } + } + + bool follow = opts.isSet("follow"); + + if(head && follow) + { + invalidCommand("can't use -f | --follow option with -h | --head option"); + return; + } + + if(filename == "log") + { + showLog(id, reader, tail, follow, lineCount); + } + else + { + showFile(id, reader, filename, head, tail, follow, lineCount); + } + } + catch(const Ice::Exception& ex) + { + exception(ex); + } +} + +void +Parser::showFile(const string& id, const string& reader, const string& filename, + bool head, bool tail, bool follow, int lineCount) +{ + + int maxBytes = _communicator->getProperties()->getPropertyAsIntWithDefault("Ice.MessageSizeMax", 1024) * 1024; + + FileIteratorPrx it; + + try + { + if(reader == "node") + { + if(filename == "stderr") + { + it = _session->openNodeStdErr(id, tail ? lineCount : -1); + } + else if(filename == "stdout") + { + it = _session->openNodeStdOut(id, tail ? lineCount : -1); + } + else + { + invalidCommand("invalid node log filename `" + filename + "'"); + return; + } + } + else if(reader == "registry") + { + if(filename == "stderr") + { + it = _session->openRegistryStdErr(id, tail ? lineCount : -1); + } + else if(filename == "stdout") + { + it = _session->openRegistryStdOut(id, tail ? lineCount : -1); + } + else + { + invalidCommand("invalid registry log filename `" + filename + "'"); + return; + } + } + else if(reader == "server") + { + if(filename == "stderr") + { + it = _session->openServerStdErr(id, tail ? lineCount : -1); + } + else if(filename == "stdout") + { + it = _session->openServerStdOut(id, tail ? lineCount : -1); + } + else + { + it = _session->openServerLog(id, filename, tail ? lineCount : -1); + } + } + + resetInterrupt(); + Ice::StringSeq lines; + if(head) + { + assert(!follow); + + int i = 0; + bool eof = false; + while(!interrupted() && !eof && i < lineCount) + { + eof = it->read(maxBytes, lines); + for(Ice::StringSeq::const_iterator p = lines.begin(); i < lineCount && p != lines.end(); ++p, ++i) + { + outputNewline(); + outputString(*p); + flushOutput(); + } + } + } + else + { + bool eof = false; + while(!interrupted() && !eof) + { + eof = it->read(maxBytes, lines); + for(Ice::StringSeq::const_iterator p = lines.begin(); p != lines.end(); ++p) + { + outputNewline(); + outputString(*p); + flushOutput(); + } + } + } + + if(follow) + { + while(!interrupted()) + { + bool eof = it->read(maxBytes, lines); + for(Ice::StringSeq::const_iterator p = lines.begin(); p != lines.end(); ++p) + { + outputString(*p); + if((p + 1) != lines.end()) + { + outputNewline(); + } + else + { + flushOutput(); + } + } + + if(eof) + { + Lock sync(*this); + if(_interrupted) + { + break; + } + timedWait(IceUtil::Time::seconds(5)); + } + } + } + + if(lines.empty() || !lines.back().empty()) + { + outputNewline(); + flushOutput(); + } + + it->destroy(); + } + catch(...) + { + if(it != 0) + { + try + { + it->destroy(); + } + catch(...) + { + } + } + throw; + } +} + +void +Parser::showLog(const string& id, const string& reader, bool tail, bool follow, int lineCount) +{ + outputNewline(); + + Ice::ObjectPrx admin; + + if(reader == "server") + { + admin = _admin->getServerAdmin(id); + } + else if(reader == "node") + { + admin = _admin->getNodeAdmin(id); + } + else if(reader == "registry") + { + admin = _admin->getRegistryAdmin(id); + } + + if(admin == 0) + { + error("cannot retrieve Admin proxy for " + reader + " `" + id + "'"); + return; + } + + Ice::LoggerAdminPrx loggerAdmin; + + try + { + loggerAdmin = Ice::LoggerAdminPrx::checkedCast(admin, "Logger"); + } + catch(const Ice::Exception&) + { + } + + if(loggerAdmin == 0) + { + error("cannot retrieve Logger admin facet for " + reader + " `" + id + "'"); + return; + } + + if(follow) + { + Ice::ObjectPrx adminCallbackTemplate = _session->getAdminCallbackTemplate(); + + if(adminCallbackTemplate == 0) + { + error("cannot retriever Callback template from IceGrid registry"); + return; + } + + const Ice::EndpointSeq endpoints = adminCallbackTemplate->ice_getEndpoints(); + string publishedEndpoints; + + for(Ice::EndpointSeq::const_iterator p = endpoints.begin(); p != endpoints.end(); ++p) + { + if(publishedEndpoints.empty()) + { + publishedEndpoints = (*p)->toString(); + } + else + { + publishedEndpoints += ":" + (*p)->toString(); + } + } + + _communicator->getProperties()->setProperty("RemoteLoggerAdapter.PublishedEndpoints", publishedEndpoints); + + Ice::ObjectAdapterPtr adapter = _communicator->createObjectAdapter("RemoteLoggerAdapter"); + + _session->ice_getConnection()->setAdapter(adapter); + + Ice::Identity id; + ostringstream name; + name << "RemoteLogger-" << loggerCallbackCount++; + id.name = name.str(); + id.category = adminCallbackTemplate->ice_getIdentity().category; + + RemoteLoggerIPtr servant = new RemoteLoggerI; + Ice::RemoteLoggerPrx prx = + Ice::RemoteLoggerPrx::uncheckedCast(adapter->add(servant, id)); + adapter->activate(); + + loggerAdmin->attachRemoteLogger(prx, Ice::LogMessageTypeSeq(), Ice::StringSeq(), tail ? lineCount : -1); + + resetInterrupt(); + { + Lock lock(*this); + while(!_interrupted) + { + wait(); + } + } + + servant->destroy(); + adapter->destroy(); + + try + { + loggerAdmin->detachRemoteLogger(prx); + } + catch(const Ice::ObjectNotExistException&) + { + // ignored + } + } + else + { + string prefix; + const Ice::LogMessageSeq logMessages = loggerAdmin->getLog(Ice::LogMessageTypeSeq(), Ice::StringSeq(), + tail ? lineCount : -1, prefix); + + for(Ice::LogMessageSeq::const_iterator p = logMessages.begin(); p != logMessages.end(); ++p) + { + printLogMessage(prefix, *p); + } + } +} + +void +Parser::showBanner() +{ + consoleOut << "Ice " << ICE_STRING_VERSION << " Copyright (c) 2003-2016 ZeroC, Inc." << endl; +} + +void +Parser::showCopying() +{ + consoleOut << "This command is not implemented." << endl; +} + +void +Parser::showWarranty() +{ + consoleOut << "This command is not implemented." << 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::invalidCommand(const char* s) +{ + error(s); +} + +void +Parser::invalidCommand(const string& s) +{ + error(s.c_str()); +} + +void +Parser::invalidCommand(const string& command, const string& msg) +{ + error("`" + command + "' " + msg + "\n(`" + command + " help' for more info)"); +} + +void +Parser::invalidCommand(const list<string>& s) +{ + if(s.empty()) + { + return; + } + + string cat = *s.begin(); + if(_helpCommands.find(cat) == _helpCommands.end()) + { + consoleErr << "unknown `" << cat << "' command (see `help' for more info)" << endl; + } + else if(s.size() == 1) + { + consoleErr << "invalid `" << cat << "' command (see `" << cat << " help' for more info)" << endl; + } + else + { + string cmd = *(++s.begin()); + if(_helpCommands[cat].find(cmd) == _helpCommands[cat].end()) + { + cmd = cat + " " + cmd; + consoleErr << "unknown `" << cmd << "' command (see `" << cat << " help' for more info)" << endl; + } + else + { + cmd = cat + " " + cmd; + consoleErr << "invalid `" << cmd << "' command (see `" << cmd << " help' for more info)" << endl; + } + } +} + +string +Parser::patchFailed(const Ice::StringSeq& reasons) +{ + if(reasons.size() == 1) + { + ostringstream s; + s << "the patch failed:\n" << reasons[0]; + return s.str(); + } + else + { + ostringstream os; + IceUtilInternal::Output out(os); + out.setIndent(2); + out << "the patch failed on some nodes:\n"; + for(Ice::StringSeq::const_iterator p = reasons.begin(); p != reasons.end(); ++p) + { + string reason = *p; + string::size_type beg = 0; + string::size_type end = reason.find_first_of("\n"); + if(end == string::npos) + { + end = reason.size(); + } + out << "- " << reason.substr(beg, end - beg); + out.inc(); + while(end < reason.size()) + { + beg = end + 1; + end = reason.find_first_of("\n", beg); + if(end == string::npos) + { + end = reason.size(); + } + out.newline(); + out << reason.substr(beg, end - beg); + } + out.dec(); + if(p + 1 != reasons.end()) + { + out.newline(); + } + } + return os.str(); + } +} + +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()); +} + +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; +} + +Parser::Parser(const CommunicatorPtr& communicator, + const AdminSessionPrx& session, + const AdminPrx& admin, + bool interactive) : + _communicator(communicator), + _session(session), + _admin(admin), + _interrupted(false), + _interactive(interactive) +{ + for(int i = 0; _commandsHelp[i][0]; i++) + { + const string category = _commandsHelp[i][0]; + const string cmd = _commandsHelp[i][1]; + const string help = _commandsHelp[i][2]; + _helpCommands[category][""] += help; + _helpCommands[category][cmd] += help; + } + +#ifdef _WIN32 + if(!windowsConsoleConverter) + { + windowsConsoleConverter = Ice::createWindowsStringConverter(GetConsoleOutputCP()); + } +#endif +} + +void +Parser::exception(const Ice::Exception& ex) +{ + try + { + ex.ice_throw(); + } + catch(const ApplicationNotExistException& ex) + { + error("couldn't find application `" + ex.name + "'"); + } + catch(const NodeNotExistException& ex) + { + error("couldn't find node `" + ex.name + "'"); + } + catch(const RegistryNotExistException& ex) + { + error("couldn't find registry `" + ex.name + "'"); + } + catch(const ServerNotExistException& ex) + { + error("couldn't find server `" + ex.id + "'"); + } + catch(const AdapterNotExistException& ex) + { + error("couldn't find adapter `" + ex.id + "'"); + } + catch(const ObjectNotRegisteredException& ex) + { + error("couldn't find object `" + _communicator->identityToString(ex.id) + "'"); + } + catch(const ObjectExistsException& ex) + { + error("object `" + _communicator->identityToString(ex.id) + "' already exists"); + } + catch(const DeploymentException& ex) + { + ostringstream s; + s << ex << ":\n" << ex.reason; + error(s.str()); + } + catch(const PatchException& ex) + { + error(patchFailed(ex.reasons)); + } + catch(const BadSignalException& ex) + { + ostringstream s; + s << ex.reason; + error(s.str()); + } + catch(const NodeUnreachableException& ex) + { + error("node `" + ex.name + "' couldn't be reached:\n" + ex.reason); + } + catch(const RegistryUnreachableException& ex) + { + error("registry `" + ex.name + "' couldn't be reached:\n" + ex.reason); + } + catch(const ServerUnreachableException& ex) + { + error("server `" + ex.name + "' couldn't be reached:\n" + ex.reason); + } + catch(const AccessDeniedException& ex) + { + error("couldn't update the registry, the session from `" + ex.lockUserId + "' is updating the registry"); + } + catch(const FileNotAvailableException& ex) + { + error("couldn't access file:\n" + ex.reason); + } + catch(const IceXML::ParserException& ex) + { + ostringstream s; + s << ex; + error(s.str()); + } + catch(const Ice::LocalException& ex) + { + ostringstream s; + s << "couldn't reach the IceGrid registry:\n" << ex; + error(s.str()); + } + catch(const Ice::Exception& ex) + { + ostringstream s; + s << ex; + error(s.str()); + } +} 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()); + } +} diff --git a/cpp/src/Slice/JavaUtil.cpp b/cpp/src/Slice/JavaUtil.cpp new file mode 100644 index 00000000000..cb99ca5da46 --- /dev/null +++ b/cpp/src/Slice/JavaUtil.cpp @@ -0,0 +1,5045 @@ +// ********************************************************************** +// +// 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 <Slice/JavaUtil.h> +#include <Slice/FileTracker.h> +#include <Slice/Util.h> +#include <Slice/MD5.h> +#include <IceUtil/Functional.h> +#include <IceUtil/FileUtil.h> + +#include <sys/types.h> +#include <string.h> + +#ifdef _WIN32 +#include <direct.h> +#endif + +#ifndef _WIN32 +#include <unistd.h> +#endif + +using namespace std; +using namespace Slice; +using namespace IceUtil; +using namespace IceUtilInternal; + +namespace +{ + +void +hashAdd(long& hashCode, const std::string& value) +{ + for(std::string::const_iterator p = value.begin(); p != value.end(); ++p) + { + hashCode = ((hashCode << 5) + hashCode) ^ *p; + } +} + +string +typeToBufferString(const TypePtr& type) +{ + static const char* builtinBufferTable[] = + { + "java.nio.ByteBuffer", + "???", + "java.nio.ShortBuffer", + "java.nio.IntBuffer", + "java.nio.LongBuffer", + "java.nio.FloatBuffer", + "java.nio.DoubleBuffer", + "???", + "???", + "???", + "???" + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(!builtin) + { + return "???"; + } + else + { + return builtinBufferTable[builtin->kind()]; + } +} + +string +lookupKwd(const string& name) +{ + // + // Keyword list. *Must* be kept in alphabetical order. Note that checkedCast and uncheckedCast + // are not Java keywords, but are in this list to prevent illegal code being generated if + // someone defines Slice operations with that name. + // + // NOTE: Any changes made to this list must also be made in BasicStream.java. + // + static const string keywordList[] = + { + "abstract", "assert", "boolean", "break", "byte", "case", "catch", + "char", "checkedCast", "class", "clone", "const", "continue", "default", "do", + "double", "else", "enum", "equals", "extends", "false", "final", "finalize", + "finally", "float", "for", "getClass", "goto", "hashCode", "if", + "implements", "import", "instanceof", "int", "interface", "long", + "native", "new", "notify", "notifyAll", "null", "package", "private", + "protected", "public", "return", "short", "static", "strictfp", "super", "switch", + "synchronized", "this", "throw", "throws", "toString", "transient", + "true", "try", "uncheckedCast", "void", "volatile", "wait", "while" + }; + bool found = binary_search(&keywordList[0], + &keywordList[sizeof(keywordList) / sizeof(*keywordList)], + name); + return found ? "_" + name : name; +} + +// +// Split a scoped name into its components and return the components as a list of (unscoped) identifiers. +// +static StringList +splitScopedName(const string& scoped) +{ + assert(scoped[0] == ':'); + StringList ids; + string::size_type next = 0; + string::size_type pos; + while((pos = scoped.find("::", next)) != string::npos) + { + pos += 2; + if(pos != scoped.size()) + { + string::size_type endpos = scoped.find("::", pos); + if(endpos != string::npos) + { + ids.push_back(scoped.substr(pos, endpos - pos)); + } + } + next = pos; + } + if(next != scoped.size()) + { + ids.push_back(scoped.substr(next)); + } + else + { + ids.push_back(""); + } + + return ids; +} + +class MetaDataVisitor : public ParserVisitor +{ +public: + + virtual bool visitUnitStart(const UnitPtr& p) + { + static const string prefix = "java:"; + + // + // Validate global metadata in the top-level file and all included files. + // + StringList files = p->allFiles(); + + for(StringList::iterator q = files.begin(); q != files.end(); ++q) + { + string file = *q; + DefinitionContextPtr dc = p->findDefinitionContext(file); + assert(dc); + StringList globalMetaData = dc->getMetaData(); + for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end();) + { + string s = *r++; + if(s.find(prefix) == 0) + { + static const string packagePrefix = "java:package:"; + static const string checksumPrefix = "java:checksum:"; + if(s.find(packagePrefix) == 0 && s.size() > packagePrefix.size()) + { + continue; + } + else if(s.find(checksumPrefix) == 0 && s.size() > checksumPrefix.size()) + { + continue; + } + else + { + dc->warning(InvalidMetaData, file, "", "ignoring invalid global metadata `" + s + "'"); + globalMetaData.remove(s); + continue; + } + }; + } + dc->setMetaData(globalMetaData); + } + return true; + } + + virtual bool visitModuleStart(const ModulePtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + return true; + } + + virtual void visitClassDecl(const ClassDeclPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + } + + virtual bool visitClassDefStart(const ClassDefPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + return true; + } + + virtual bool visitExceptionStart(const ExceptionPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + return true; + } + + virtual bool visitStructStart(const StructPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + return true; + } + + virtual void visitOperation(const OperationPtr& p) + { + TypePtr returnType = p->returnType(); + StringList metaData = getMetaData(p); + + UnitPtr unit = p->unit(); + string file = p->file(); + DefinitionContextPtr dc = unit->findDefinitionContext(p->file()); + + if(!returnType) + { + for(StringList::const_iterator q = metaData.begin(); q != metaData.end();) + { + string s = *q++; + if(s.find("java:type:", 0) == 0) + { + dc->warning(InvalidMetaData, p->file(), p->line(), "ignoring invalid metadata `" + s + + "' for operation with void return type"); + metaData.remove(s); + continue; + } + } + } + else + { + metaData = validateType(returnType, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + } + p->setMetaData(metaData); + + ParamDeclList params = p->parameters(); + for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q) + { + metaData = getMetaData(*q); + metaData = validateType((*q)->type(), metaData, p->file(), (*q)->line()); + metaData = validateGetSet((*q)->type(), metaData, p->file(), (*q)->line()); + (*q)->setMetaData(metaData); + } + } + + virtual void visitDataMember(const DataMemberPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p->type(), metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + } + + virtual void visitSequence(const SequencePtr& p) + { + static const string protobuf = "java:protobuf:"; + static const string serializable = "java:serializable:"; + static const string bytebuffer = "java:buffer"; + StringList metaData = getMetaData(p); + StringList newMetaData; + + const string file = p->file(); + const string line = p->line(); + const UnitPtr unit = p->unit(); + const DefinitionContextPtr dc = unit->findDefinitionContext(file); + + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ) + { + string s = *q++; + + if(s.find(protobuf) == 0 || s.find(serializable) == 0) + { + // + // Remove from list so validateType does not try to handle as well. + // + metaData.remove(s); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(!builtin || builtin->kind() != Builtin::KindByte) + { + dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + s + "': " + + "this metadata can only be used with a byte sequence"); + continue; + } + newMetaData.push_back(s); + } + else if(s.find(bytebuffer) == 0) + { + metaData.remove(s); + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(!builtin || + (builtin->kind() != Builtin::KindByte && builtin->kind() != Builtin::KindShort && + builtin->kind() != Builtin::KindInt && builtin->kind() != Builtin::KindLong && + builtin->kind() != Builtin::KindFloat && builtin->kind() != Builtin::KindDouble)) + { + dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + s + "': " + + "this metadata can not be used with this type"); + continue; + } + newMetaData.push_back(s); + } + } + + metaData = validateType(p, metaData, file, line); + metaData = validateGetSet(p, metaData, file, line); + newMetaData.insert(newMetaData.begin(), metaData.begin(), metaData.end()); + p->setMetaData(newMetaData); + } + + virtual void visitDictionary(const DictionaryPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + } + + virtual void visitEnum(const EnumPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + } + + virtual void visitConst(const ConstPtr& p) + { + StringList metaData = getMetaData(p); + metaData = validateType(p, metaData, p->file(), p->line()); + metaData = validateGetSet(p, metaData, p->file(), p->line()); + p->setMetaData(metaData); + } + +private: + + StringList getMetaData(const ContainedPtr& cont) + { + static const string prefix = "java:"; + + StringList metaData = cont->getMetaData(); + StringList result; + + UnitPtr unit = cont->container()->unit(); + string file = cont->file(); + DefinitionContextPtr dc = unit->findDefinitionContext(file); + assert(dc); + + for(StringList::const_iterator p = metaData.begin(); p != metaData.end(); ++p) + { + string s = *p; + if(s.find(prefix) == 0) + { + string::size_type pos = s.find(':', prefix.size()); + if(pos == string::npos) + { + if(s.size() > prefix.size()) + { + string rest = s.substr(prefix.size()); + if(rest == "getset") + { + result.push_back(s); + continue; + } + else if(rest == "buffer") + { + result.push_back(s); + continue; + } + else if(rest == "tie") + { + result.push_back(s); + continue; + } + else if(rest == "UserException") + { + result.push_back(s); + continue; + } + else if(rest == "optional") + { + result.push_back(s); + continue; + } + } + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "type") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "serializable") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "protobuf") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "serialVersionUID") + { + result.push_back(s); + continue; + } + else if(s.substr(prefix.size(), pos - prefix.size()) == "implements") + { + result.push_back(s); + continue; + } + + dc->warning(InvalidMetaData, cont->file(), cont->line(), "ignoring invalid metadata `" + s + "'"); + } + else + { + result.push_back(s); + continue; + } + } + + return result; + } + + StringList validateType(const SyntaxTreeBasePtr& p, const StringList& metaData, const string& file, const string& line) + { + const UnitPtr unit = p->unit(); + const DefinitionContextPtr dc = unit->findDefinitionContext(file); + assert(dc); + StringList newMetaData; + for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i) + { + // + // Type metadata ("java:type:Foo") is only supported by sequences and dictionaries. + // + if(i->find("java:type:", 0) == 0 && (!SequencePtr::dynamicCast(p) && !DictionaryPtr::dynamicCast(p))) + { + string str; + ContainedPtr cont = ContainedPtr::dynamicCast(p); + if(cont) + { + str = cont->kindOf(); + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(p); + assert(b); + str = b->typeId(); + } + dc->warning(InvalidMetaData, file, line, "invalid metadata for " + str); + } + else if(i->find("java:buffer") == 0) + { + SequencePtr seq = SequencePtr::dynamicCast(p); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + newMetaData.push_back(*i); + continue; + } + + } + + dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + *i + "'"); + } + else if(i->find("java:protobuf:") == 0 || i->find("java:serializable:") == 0) + { + // + // Only valid in sequence definition which is checked in visitSequence + // + dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + *i + "'"); + } + else if(i->find("delegate") == 0) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(p); + if(cl && cl->isDelegate()) + { + newMetaData.push_back(*i); + } + else + { + dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + *i + "'"); + } + } + else if(i->find("java:implements:") == 0) + { + if(ClassDefPtr::dynamicCast(p) || StructPtr::dynamicCast(p)) + { + newMetaData.push_back(*i); + } + else + { + dc->warning(InvalidMetaData, file, line, "ignoring invalid metadata `" + *i + "'"); + } + } + else + { + newMetaData.push_back(*i); + } + } + return newMetaData; + } + + StringList validateGetSet(const SyntaxTreeBasePtr& p, const StringList& metaData, const string& file, const string& line) + { + const UnitPtr unit = p->unit(); + const DefinitionContextPtr dc= unit->findDefinitionContext(file); + assert(dc); + StringList newMetaData; + for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i) + { + // + // The "getset" metadata can only be specified on a class, struct, exception or data member. + // + if((*i) == "java:getset" && + (!ClassDefPtr::dynamicCast(p) && !StructPtr::dynamicCast(p) && !ExceptionPtr::dynamicCast(p) && + !DataMemberPtr::dynamicCast(p))) + { + string str; + ContainedPtr cont = ContainedPtr::dynamicCast(p); + if(cont) + { + str = cont->kindOf(); + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(p); + assert(b); + str = b->typeId(); + } + dc->warning(InvalidMetaData, file, line, "invalid metadata for " + str); + continue; + } + newMetaData.push_back(*i); + } + return newMetaData; + } +}; + +} + +long +Slice::computeSerialVersionUUID(const ClassDefPtr& p) +{ + ostringstream os; + + ClassList bases = p->bases(); + os << "Name: " << p->scoped(); + + os << " Bases: ["; + for(ClassList::const_iterator i = bases.begin(); i != bases.end();) + { + os << (*i)->scoped(); + i++; + if(i != bases.end()) + { + os << ", "; + } + } + os << "]"; + + os << " Members: ["; + DataMemberList members = p->dataMembers(); + for(DataMemberList::const_iterator i = members.begin(); i != members.end();) + { + os << (*i)->name() << ":" << (*i)->type(); + i++; + if(i != members.end()) + { + os << ", "; + } + } + os << "]"; + + const string data = os.str(); + long hashCode = 5381; + hashAdd(hashCode, data); + return hashCode; +} + +long +Slice::computeSerialVersionUUID(const StructPtr& p) +{ + ostringstream os; + + os << "Name: " << p->scoped(); + os << " Members: ["; + DataMemberList members = p->dataMembers(); + for(DataMemberList::const_iterator i = members.begin(); i != members.end();) + { + os << (*i)->name() << ":" << (*i)->type(); + i++; + if(i != members.end()) + { + os << ", "; + } + } + os << "]"; + + const string data = os.str(); + long hashCode = 5381; + hashAdd(hashCode, data); + return hashCode; +} + +long +Slice::computeSerialVersionUUID(const ExceptionPtr& p) +{ + ostringstream os; + + os << "Name: " << p->scoped(); + os << " Members: ["; + DataMemberList members = p->dataMembers(); + for(DataMemberList::const_iterator i = members.begin(); i != members.end();) + { + os << (*i)->name() << ":" << (*i)->type(); + i++; + if(i != members.end()) + { + os << ", "; + } + } + os << "]"; + + const string data = os.str(); + long hashCode = 5381; + hashAdd(hashCode, data); + return hashCode; +} + +Slice::JavaOutput::JavaOutput() +{ +} + +Slice::JavaOutput::JavaOutput(ostream& os) : + Output(os) +{ +} + +Slice::JavaOutput::JavaOutput(const char* s) : + Output(s) +{ +} + +void +Slice::JavaOutput::openClass(const string& cls, const string& prefix, const string& sliceFile) +{ + string package; + string file; + string path = prefix; + + string::size_type pos = cls.rfind('.'); + if(pos != string::npos) + { + package = cls.substr(0, pos); + file = cls.substr(pos + 1); + string dir = package; + + // + // Create package directories if necessary. + // + pos = 0; + string::size_type start = 0; + do + { + if(!path.empty()) + { + path += "/"; + } + pos = dir.find('.', start); + if(pos != string::npos) + { + path += dir.substr(start, pos - start); + start = pos + 1; + } + else + { + path += dir.substr(start); + } + + IceUtilInternal::structstat st; + if(!IceUtilInternal::stat(path, &st)) + { + if(!(st.st_mode & S_IFDIR)) + { + ostringstream os; + os << "failed to create package directory `" << path + << "': file already exists and is not a directory"; + throw FileException(__FILE__, __LINE__, os.str()); + } + continue; + } + + if(IceUtilInternal::mkdir(path, 0777) != 0) + { + ostringstream os; + os << "cannot create directory `" << path << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addDirectory(path); + } + while(pos != string::npos); + } + else + { + file = cls; + } + file += ".java"; + + // + // Open class file. + // + if(!path.empty()) + { + path += "/"; + } + path += file; + + open(path.c_str()); + if(isOpen()) + { + FileTracker::instance()->addFile(path); + printHeader(); + printGeneratedHeader(*this, sliceFile); + if(!package.empty()) + { + separator(); + print("package "); + print(package.c_str()); + print(";"); + } + } + else + { + ostringstream os; + os << "cannot open file `" << path << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } +} + +void +Slice::JavaOutput::printHeader() +{ + static const char* header = +"// **********************************************************************\n" +"//\n" +"// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.\n" +"//\n" +"// This copy of Ice is licensed to you under the terms described in the\n" +"// ICE_LICENSE file included in this distribution.\n" +"//\n" +"// **********************************************************************\n" + ; + + print(header); + print("//\n"); + print("// Ice version "); + print(ICE_STRING_VERSION); + print("\n"); + print("//\n"); +} + +const string Slice::JavaCompatGenerator::_getSetMetaData = "java:getset"; + +Slice::JavaCompatGenerator::JavaCompatGenerator(const string& dir) : + _dir(dir), + _out(0) +{ +} + +Slice::JavaCompatGenerator::~JavaCompatGenerator() +{ + // If open throws an exception other generators could be left open + // during the stack unwind. + if(_out != 0) + { + close(); + } + assert(_out == 0); +} + +void +Slice::JavaCompatGenerator::open(const string& absolute, const string& file) +{ + assert(_out == 0); + + JavaOutput* out = createOutput(); + try + { + out->openClass(absolute, _dir, file); + } + catch(const FileException&) + { + delete out; + throw; + } + _out = out; +} + +void +Slice::JavaCompatGenerator::close() +{ + assert(_out != 0); + *_out << nl; + delete _out; + _out = 0; +} + +Output& +Slice::JavaCompatGenerator::output() const +{ + assert(_out != 0); + return *_out; +} + +// +// If the passed name is a scoped name, return the identical scoped name, +// but with all components that are Java keywords replaced by +// their "_"-prefixed version; otherwise, if the passed name is +// not scoped, but a Java keyword, return the "_"-prefixed name; +// otherwise, return the name unchanged. +// +string +Slice::JavaCompatGenerator::fixKwd(const string& name) const +{ + if(name.empty()) + { + return name; + } + if(name[0] != ':') + { + return lookupKwd(name); + } + StringList ids = splitScopedName(name); + transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd)); + stringstream result; + for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i) + { + result << "::" + *i; + } + return result.str(); +} + +string +Slice::JavaCompatGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix) const +{ + string result; + string::size_type start = 0; + string fscoped = fixKwd(scoped); + + // + // Skip leading "::" + // + if(fscoped[start] == ':') + { + assert(fscoped[start + 1] == ':'); + start += 2; + } + + // + // Convert all occurrences of "::" to "." + // + string::size_type pos; + do + { + pos = fscoped.find(':', start); + string fix; + if(pos == string::npos) + { + string s = fscoped.substr(start); + if(!s.empty()) + { + fix = prefix + fixKwd(s) + suffix; + } + } + else + { + assert(fscoped[pos + 1] == ':'); + fix = fixKwd(fscoped.substr(start, pos - start)); + start = pos + 2; + } + + if(!result.empty() && !fix.empty()) + { + result += "."; + } + result += fix; + } + while(pos != string::npos); + + return result; +} + +string +Slice::JavaCompatGenerator::getPackagePrefix(const ContainedPtr& cont) const +{ + UnitPtr unit = cont->container()->unit(); + string file = cont->file(); + assert(!file.empty()); + + map<string, string>::const_iterator p = _filePackagePrefix.find(file); + if(p != _filePackagePrefix.end()) + { + return p->second; + } + + static const string prefix = "java:package:"; + DefinitionContextPtr dc = unit->findDefinitionContext(file); + assert(dc); + string q = dc->findMetaData(prefix); + if(!q.empty()) + { + q = q.substr(prefix.size()); + } + _filePackagePrefix[file] = q; + return q; +} + +string +Slice::JavaCompatGenerator::getPackage(const ContainedPtr& cont) const +{ + string scope = convertScopedName(cont->scope()); + string prefix = getPackagePrefix(cont); + if(!prefix.empty()) + { + if(!scope.empty()) + { + return prefix + "." + scope; + } + else + { + return prefix; + } + } + + return scope; +} + +string +Slice::JavaCompatGenerator::getAbsolute(const ContainedPtr& cont, + const string& package, + const string& prefix, + const string& suffix) const +{ + string name = cont->name(); + if(prefix == "" && suffix == "") + { + name = fixKwd(name); + } + string contPkg = getPackage(cont); + if(contPkg == package) + { + return prefix + name + suffix; + } + else if(!contPkg.empty()) + { + return contPkg + "." + prefix + name + suffix; + } + else + { + return prefix + name + suffix; + } +} + +string +Slice::JavaCompatGenerator::getStaticId(const TypePtr& type, const string& package) const +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + + assert((b && b->usesClasses()) || cl); + + if(b) + { + return "Ice.ObjectImpl.ice_staticId()"; + } + else if(cl->isInterface()) + { + return getAbsolute(cl, package, "_", "Disp") + ".ice_staticId()"; + } + else + { + return getAbsolute(cl, package) + ".ice_staticId()"; + } +} + +bool +Slice::JavaCompatGenerator::useOptionalMapping(const OperationPtr& p) +{ + // + // The "java:optional" metadata can be applied to an operation or its + // interface to force the mapping to use the Ice.Optional types. + // + // Without the tag, parameters use the normal (non-optional) mapping. + // + static const string tag = "java:optional"; + + ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); + assert(cl); + + return p->hasMetaData(tag) || cl->hasMetaData(tag); +} + +string +Slice::JavaCompatGenerator::getOptionalFormat(const TypePtr& type) +{ + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + if(bp) + { + switch(bp->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + { + return "Ice.OptionalFormat.F1"; + } + case Builtin::KindShort: + { + return "Ice.OptionalFormat.F2"; + } + case Builtin::KindInt: + case Builtin::KindFloat: + { + return "Ice.OptionalFormat.F4"; + } + case Builtin::KindLong: + case Builtin::KindDouble: + { + return "Ice.OptionalFormat.F8"; + } + case Builtin::KindString: + { + return "Ice.OptionalFormat.VSize"; + } + case Builtin::KindObject: + { + return "Ice.OptionalFormat.Class"; + } + case Builtin::KindObjectProxy: + { + return "Ice.OptionalFormat.FSize"; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + case Builtin::KindValue: + { + return "Ice.OptionalFormat.Class"; + } + } + } + + if(EnumPtr::dynamicCast(type)) + { + return "Ice.OptionalFormat.Size"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return seq->type()->isVariableLength() ? "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ? + "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return st->isVariableLength() ? "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize"; + } + + if(ProxyPtr::dynamicCast(type)) + { + return "Ice.OptionalFormat.FSize"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert(cl); + return "Ice.OptionalFormat.Class"; +} + +string +Slice::JavaCompatGenerator::typeToString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal, + bool optional) const +{ + static const char* builtinTable[] = + { + "byte", + "boolean", + "short", + "int", + "long", + "float", + "double", + "String", + "Ice.Object", + "Ice.ObjectPrx", + "java.lang.Object", + "Ice.Object" // Ice.Value + }; + static const char* builtinHolderTable[] = + { + "Ice.ByteHolder", + "Ice.BooleanHolder", + "Ice.ShortHolder", + "Ice.IntHolder", + "Ice.LongHolder", + "Ice.FloatHolder", + "Ice.DoubleHolder", + "Ice.StringHolder", + "Ice.ObjectHolder", + "Ice.ObjectPrxHolder", + "Ice.LocalObjectHolder", + "Ice.ObjectHolder" // Ice.ValueHolder + }; + static const char* builtinOptionalTable[] = + { + "Ice.ByteOptional", + "Ice.BooleanOptional", + "Ice.ShortOptional", + "Ice.IntOptional", + "Ice.LongOptional", + "Ice.FloatOptional", + "Ice.DoubleOptional", + "???", + "???", + "???", + "???", + "???" + }; + + if(!type) + { + assert(mode == TypeModeReturn); + return "void"; + } + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + if(optional) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + return builtinOptionalTable[builtin->kind()]; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + break; + } + } + } + else + { + if(mode == TypeModeOut) + { + return builtinHolderTable[builtin->kind()]; + } + else + { + return builtinTable[builtin->kind()]; + } + } + } + + if(optional) + { + return "Ice.Optional<" + typeToString(type, TypeModeIn, package, metaData, formal) + ">"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + return getAbsolute(cl, package, "", mode == TypeModeOut ? "Holder" : ""); + } + + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(proxy) + { + return getAbsolute(proxy->_class(), package, "", mode == TypeModeOut ? "PrxHolder" : "Prx"); + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + if(mode == TypeModeOut) + { + // + // Only use the type's generated holder if the instance and + // formal types match. + // + string instanceType, formalType; + getDictionaryTypes(dict, "", metaData, instanceType, formalType); + string origInstanceType, origFormalType; + getDictionaryTypes(dict, "", StringList(), origInstanceType, origFormalType); + if(formalType == origFormalType && instanceType == origInstanceType) + { + return getAbsolute(dict, package, "", "Holder"); + } + + // + // The custom type may or may not be compatible with the type used + // in the generated holder. We use a generic holder that holds a value of the + // formal custom type. + // + return string("Ice.Holder<") + formalType + " >"; + } + else + { + string instanceType, formalType; + getDictionaryTypes(dict, package, metaData, instanceType, formalType); + return formal ? formalType : instanceType; + } + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + if(mode == TypeModeOut) + { + string instanceType, formalType; + getSequenceTypes(seq, "", metaData, instanceType, formalType); + if(sequenceHasHolder(seq)) + { + // + // Only use the type's generated holder if the instance and + // formal types match. + // + string origInstanceType, origFormalType; + getSequenceTypes(seq, "", StringList(), origInstanceType, origFormalType); + if(formalType == origFormalType && instanceType == origInstanceType) + { + return getAbsolute(seq, package, "", "Holder"); + } + } + + // + // The custom type may or may not be compatible with the type used + // in the generated holder. We use a generic holder that holds a value of the + // formal custom type. + // + return string("Ice.Holder<") + formalType + " >"; + } + else + { + string instanceType, formalType; + getSequenceTypes(seq, package, metaData, instanceType, formalType); + return formal ? formalType : instanceType; + } + } + + ContainedPtr contained = ContainedPtr::dynamicCast(type); + if(contained) + { + if(mode == TypeModeOut) + { + return getAbsolute(contained, package, "", "Holder"); + } + else + { + return getAbsolute(contained, package); + } + } + + return "???"; +} + +string +Slice::JavaCompatGenerator::typeToObjectString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal) const +{ + static const char* builtinTable[] = + { + "java.lang.Byte", + "java.lang.Boolean", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + "java.lang.String", + "Ice.Object", + "Ice.ObjectPrx", + "java.lang.Object", + "Ice.Object" // Ice.Value + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin && mode != TypeModeOut) + { + return builtinTable[builtin->kind()]; + } + + return typeToString(type, mode, package, metaData, formal); +} + +void +Slice::JavaCompatGenerator::writeMarshalUnmarshalCode(Output& out, + const string& package, + const TypePtr& type, + OptionalMode mode, + bool optionalMapping, + int tag, + const string& param, + bool marshal, + int& iter, + bool holder, + const string& customStream, + const StringList& metaData, + const string& patchParams) +{ + string stream = customStream; + if(stream.empty()) + { + stream = marshal ? "ostr" : "istr"; + } + + string v; + if(holder) + { + v = param + ".value"; + } + else + { + v = param; + } + + const bool optionalParam = mode == OptionalInParam || mode == OptionalOutParam || mode == OptionalReturnParam; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeByte(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeByte(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readByte(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readByte();"; + } + } + break; + } + case Builtin::KindBool: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeBool(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeBool(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readBool(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readBool();"; + } + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeShort(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeShort(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readShort(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readShort();"; + } + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeInt(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeInt(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readInt(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readInt();"; + } + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeLong(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeLong(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readLong(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readLong();"; + } + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeFloat(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeFloat(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readFloat(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readFloat();"; + } + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeDouble(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeDouble(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readDouble(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readDouble();"; + } + } + break; + } + case Builtin::KindString: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeString(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeString(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readString(" << tag << ", " << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readString();"; + } + } + break; + } + case Builtin::KindObject: + case Builtin::KindValue: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeValue(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeValue(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readValue(" << tag << ", " << param << ");"; + } + else if(holder && mode == OptionalNone) + { + out << nl << stream << ".readValue(" << param << ");"; + } + else + { + if(patchParams.empty()) + { + out << nl << stream << ".readValue(new Patcher());"; + } + else + { + out << nl << stream << ".readValue(" << patchParams << ");"; + } + } + } + break; + } + case Builtin::KindObjectProxy: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeProxy(" << tag << ", " << v << ");"; + } + else if(mode == OptionalMember) + { + out << nl << "int pos = " << stream << ".startSize();"; + out << nl << stream << ".writeProxy(" << v << ");"; + out << nl << stream << ".endSize(pos);"; + } + else + { + out << nl << stream << ".writeProxy(" << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << stream << ".readProxy(" << tag << ", " << v << ");"; + } + else if(mode == OptionalMember) + { + out << nl << stream << ".skip(4);"; + out << nl << v << " = " << stream << ".readProxy();"; + } + else + { + out << nl << v << " = " << stream << ".readProxy();"; + } + } + break; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + return; + } + + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + string typeS = typeToString(type, TypeModeIn, package); + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << v << " != null && " << v << ".isSet() && " << stream << ".writeOptional(" + << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << "int pos = " << stream << ".startSize();"; + out << nl << typeS << "Helper.write(" << stream << ", " << v << ".get());"; + out << nl << stream << ".endSize(pos);"; + out << eb; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << "int pos = " << stream << ".startSize();"; + out << nl << typeS << "Helper.write(" << stream << ", " << v << ");"; + out << nl << stream << ".endSize(pos);"; + out << eb; + } + } + else if(mode == OptionalMember) + { + out << nl << "int pos = " << stream << ".startSize();"; + out << nl << typeS << "Helper.write(" << stream << ", " << v << ");"; + out << nl << stream << ".endSize(pos);"; + } + else + { + out << nl << typeS << "Helper.write(" << stream << ", " << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << stream << ".skip(4);"; + out << nl << v << ".set(" << typeS << "Helper.read(" << stream << "));"; + out << eb; + if(mode == OptionalOutParam) + { + out << nl << "else"; + out << sb; + out << nl << v << ".clear();"; + out << eb; + } + } + else if(mode == OptionalMember) + { + out << nl << stream << ".skip(4);"; + out << nl << v << " = " << typeS << "Helper.read(" << stream << ");"; + } + else + { + out << nl << v << " = " << typeS << "Helper.read(" << stream << ");"; + } + } + return; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeValue(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".writeValue(" << v << ");"; + } + } + else + { + if(optionalParam) + { + string typeS = typeToString(type, TypeModeIn, package); + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << stream << ".readValue(new Ice.OptionalObject(" << v << ", " << typeS << ".class, " + << getStaticId(type, package) << "));"; + out << eb; + if(mode == OptionalOutParam) + { + out << nl << "else"; + out << sb; + out << nl << v << ".clear();"; + out << eb; + } + } + else + { + if(holder && mode == OptionalNone) + { + out << nl << stream << ".readValue(" << param << ");"; + } + else + { + if(patchParams.empty()) + { + out << nl << stream << ".readValue(new Patcher());"; + } + else + { + out << nl << stream << ".readValue(" << patchParams << ");"; + } + } + } + } + return; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + if(marshal) + { + if(optionalParam || mode == OptionalMember) + { + string val; + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << v << " != null && " << v << ".isSet() && " << stream << ".writeOptional(" + << tag << ", " << getOptionalFormat(type) << "))"; + val = v + ".get()"; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) + << "))"; + val = v; + } + out << sb; + } + else + { + val = v; + } + + if(st->isVariableLength()) + { + out << nl << "int pos = " << stream << ".startSize();"; + out << nl << typeS << ".ice_write(" << stream << ", " << val << ");"; + out << nl << stream << ".endSize(pos);"; + } + else + { + out << nl << stream << ".writeSize(" << st->minWireSize() << ");"; + out << nl << typeS << ".ice_write(" << stream << ", " << val << ");"; + } + if(optionalParam) + { + out << eb; + } + } + else + { + out << nl << typeS << ".ice_write(" << stream << ", " << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + + if(st->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; + } + + out << nl << typeS << " tmpOpt = new " << typeS << "();"; + out << nl << "tmpOpt.ice_readMembers(" << stream << ");"; + out << nl << v << ".set(tmpOpt);"; + + out << eb; + + if(mode == OptionalOutParam) + { + out << nl << "else"; + out << sb; + out << nl << v << ".clear();"; + out << eb; + } + } + else if(mode == OptionalMember) + { + if(st->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; + } + out << nl << v << " = " << typeS << ".ice_read(" << stream << ");"; + } + else + { + out << nl << v << " = " << typeS << ".ice_read(" << stream << ");"; + } + } + return; + } + + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << v << " != null && " << v << ".isSet() && " << stream << ".writeOptional(" + << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ".ice_write(" << stream << ", " << v << ".get());"; + out << eb; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ".ice_write(" << stream << ", " << v << ");"; + out << eb; + } + } + else + { + out << nl << typeS << ".ice_write(" << stream << ", " << v << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << v << ".set(" << typeS << ".ice_read(" << stream << "));"; + out << eb; + if(mode == OptionalOutParam) + { + out << nl << "else"; + out << sb; + out << nl << v << ".clear();"; + out << eb; + } + } + else + { + out << nl << v << " = " << typeS << ".ice_read(" << stream << ");"; + } + } + return; + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + if(optionalParam || mode == OptionalMember) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + TypePtr keyType = dict->keyType(); + TypePtr valueType = dict->valueType(); + + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << v << " != null && " << v << ".isSet() && " << stream << ".writeOptional(" + << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) + << "))"; + out << sb; + } + } + + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + string d = optionalParam && optionalMapping ? v + ".get()" : v; + out << nl << "int pos = " << stream << ".startSize();"; + writeDictionaryMarshalUnmarshalCode(out, package, dict, d, marshal, iter, true, customStream, metaData); + out << nl << stream << ".endSize(pos);"; + } + else + { + const size_t wireSize = keyType->minWireSize() + valueType->minWireSize(); + string tmpName; + if(optionalParam && optionalMapping) + { + tmpName = "optDict"; + out << nl << "final " << typeS << ' ' << tmpName << " = " << v << ".get();"; + } + else + { + tmpName = v; + } + out << nl << "final int optSize = " << tmpName << " == null ? 0 : " << tmpName << ".size();"; + out << nl << stream << ".writeSize(optSize > 254 ? optSize * " << wireSize + << " + 5 : optSize * " << wireSize << " + 1);"; + writeDictionaryMarshalUnmarshalCode(out, package, dict, tmpName, marshal, iter, true, customStream, metaData); + } + + if(optionalParam) + { + out << eb; + } + } + else + { + string tmpName; + + if(optionalParam) + { + tmpName = "optDict"; + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ' ' << tmpName << ';'; + } + else + { + tmpName = v; + } + + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; + } + + writeDictionaryMarshalUnmarshalCode(out, package, dict, tmpName, marshal, iter, true, customStream, metaData); + + if(optionalParam) + { + out << nl << v << ".set(" << tmpName << ");"; + out << eb; + if(mode == OptionalOutParam) + { + out << nl << "else"; + out << sb; + out << nl << v << ".clear();"; + out << eb; + } + } + } + } + else + { + writeDictionaryMarshalUnmarshalCode(out, package, dict, v, marshal, iter, true, customStream, metaData); + } + return; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + if(optionalParam || mode == OptionalMember) + { + string typeS = typeToString(type, TypeModeIn, package, metaData); + TypePtr elemType = seq->type(); + BuiltinPtr elemBuiltin = BuiltinPtr::dynamicCast(elemType); + + if(optionalParam && elemBuiltin && elemBuiltin->kind() != Builtin::KindObject && + elemBuiltin->kind() != Builtin::KindObjectProxy && elemBuiltin->kind() != Builtin::KindValue && + !hasTypeMetaData(seq, metaData)) + { + static const char* builtinTable[] = + { + "Byte", + "Bool", + "Short", + "Int", + "Long", + "Float", + "Double", + "String", + "???", + "???", + "???" + }; + + switch(elemBuiltin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + case Builtin::KindString: + { + string bs = builtinTable[elemBuiltin->kind()]; + + if(marshal) + { + out << nl << stream << ".write" << bs << "Seq(" << tag << ", " << v << ");"; + } + else + { + out << nl << stream << ".read" << bs << "Seq(" << tag << ", " << v << ");"; + } + return; + } + case Builtin::KindValue: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + } + + string ignore; + const size_t wireSize = elemType->minWireSize(); + + if(marshal) + { + if(optionalParam) + { + if(optionalMapping) + { + out << nl << "if(" << v << " != null && " << v << ".isSet() && " << stream << ".writeOptional(" + << tag << ", " << getOptionalFormat(type) << "))"; + } + else + { + out << nl << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) + << "))"; + } + + out << sb; + } + + if(elemType->isVariableLength()) + { + string s = optionalParam && optionalMapping ? v + ".get()" : v; + out << nl << "int pos = " << stream << ".startSize();"; + writeSequenceMarshalUnmarshalCode(out, package, seq, s, marshal, iter, true, customStream, metaData); + out << nl << stream << ".endSize(pos);"; + } + else if(findMetaData("java:type:", metaData, ignore) || + findMetaData("java:type:", seq->getMetaData(), ignore)) + { + // + // The sequence is an instance of java.util.List<E>, where E is a fixed-size type. + // If the element type is bool or byte, we do NOT write an extra size. + // + + string tmpName; + if(optionalParam && optionalMapping) + { + tmpName = "optSeq"; + out << nl << "final " << typeS << ' ' << tmpName << " = " << v << ".get();"; + } + else + { + tmpName = v; + } + + if(wireSize > 1) + { + out << nl << "final int optSize = " << tmpName << " == null ? 0 : " << tmpName << ".size();"; + out << nl << stream << ".writeSize(optSize > 254 ? optSize * " << wireSize + << " + 5 : optSize * " << wireSize << " + 1);"; + } + writeSequenceMarshalUnmarshalCode(out, package, seq, tmpName, marshal, iter, true, customStream, metaData); + } + else if(findMetaData("java:protobuf:", seq->getMetaData(), ignore) || + findMetaData("java:serializable:", seq->getMetaData(), ignore)) + { + // + // This just writes a byte sequence. + // + string s = optionalParam && optionalMapping ? v + ".get()" : v; + writeSequenceMarshalUnmarshalCode(out, package, seq, s, marshal, iter, true, customStream, metaData); + } + else + { + // + // At this point we have a regular Java array of a fixed-size type. + // + + string tmpName; + if(optionalParam && optionalMapping) + { + tmpName = "optSeq"; + out << nl << "final " << typeS << ' ' << tmpName << " = " << v << ".get();"; + } + else + { + tmpName = v; + } + + if(wireSize > 1) + { + out << nl << "final int optSize = " << tmpName << " == null ? 0 : " << tmpName << ".length;"; + out << nl << stream << ".writeSize(optSize > 254 ? optSize * " << wireSize + << " + 5 : optSize * " << wireSize << " + 1);"; + } + + writeSequenceMarshalUnmarshalCode(out, package, seq, tmpName, marshal, iter, true, customStream, metaData); + } + + if(optionalParam) + { + out << eb; + } + } + else + { + string tmpName; + if(optionalParam) + { + tmpName = "optSeq"; + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ' ' << tmpName << ';'; + } + else + { + tmpName = v; + } + + if(elemType->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else if(wireSize > 1) + { + if(findMetaData("java:type:", metaData, ignore) || + findMetaData("java:type:", seq->getMetaData(), ignore)) + { + // + // The sequence is an instance of java.util.List<E>, where E is a fixed-size type. + // + + out << nl << stream << ".skipSize();"; + } + else if(!findMetaData("java:protobuf:", seq->getMetaData(), ignore) && + !findMetaData("java:serializable:", seq->getMetaData(), ignore)) + { + out << nl << stream << ".skipSize();"; + } + } + + writeSequenceMarshalUnmarshalCode(out, package, seq, tmpName, marshal, iter, true, customStream, metaData); + + if(optionalParam) + { + out << nl << v << ".set(" << tmpName << ");"; + out << eb; + if(mode == OptionalOutParam) + { + out << nl << "else"; + out << sb; + out << nl << v << ".clear();"; + out << eb; + } + } + } + } + else + { + writeSequenceMarshalUnmarshalCode(out, package, seq, v, marshal, iter, true, customStream, metaData); + } + return; + } + + ConstructedPtr constructed = ConstructedPtr::dynamicCast(type); + assert(constructed); + string typeS = getAbsolute(constructed, package, "", "Helper"); + if(marshal) + { + out << nl << typeS << ".write(" << stream << ", " << v << ");"; + } + else + { + out << nl << v << " = " << typeS << ".read(" << stream << ");"; + } +} + +void +Slice::JavaCompatGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, + const string& package, + const DictionaryPtr& dict, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const string& customStream, + const StringList& metaData) +{ + string stream = customStream; + if(stream.empty()) + { + stream = marshal ? "ostr" : "istr"; + } + + string v = param; + + string instanceType; + + // + // We have to determine whether it's possible to use the + // type's generated helper class for this marshal/unmarshal + // task. Since the user may have specified a custom type in + // metadata, it's possible that the helper class is not + // compatible and therefore we'll need to generate the code + // in-line instead. + // + // Specifically, there may be "local" metadata (i.e., from + // a data member or parameter definition) that overrides the + // original type. We'll compare the mapped types with and + // without local metadata to determine whether we can use + // the helper. + // + string formalType; + getDictionaryTypes(dict, "", metaData, instanceType, formalType); + string origInstanceType, origFormalType; + getDictionaryTypes(dict, "", StringList(), origInstanceType, origFormalType); + if((formalType != origFormalType) || (!marshal && instanceType != origInstanceType)) + { + useHelper = false; + } + + // + // If we can use the helper, it's easy. + // + if(useHelper) + { + string typeS = getAbsolute(dict, package, "", "Helper"); + if(marshal) + { + out << nl << typeS << ".write(" << stream << ", " << v << ");"; + } + else + { + out << nl << v << " = " << typeS << ".read(" << stream << ");"; + } + return; + } + + TypePtr key = dict->keyType(); + TypePtr value = dict->valueType(); + + string keyS = typeToString(key, TypeModeIn, package); + string valueS = typeToString(value, TypeModeIn, package); + + ostringstream o; + o << iter; + string iterS = o.str(); + iter++; + + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << "ostr.writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "ostr.writeSize(" << v << ".size());"; + string keyObjectS = typeToObjectString(key, TypeModeIn, package); + string valueObjectS = typeToObjectString(value, TypeModeIn, package); + out << nl << "for(java.util.Map.Entry<" << keyObjectS << ", " << valueObjectS << "> e : " << v + << ".entrySet())"; + out << sb; + for(int i = 0; i < 2; i++) + { + string arg; + TypePtr type; + if(i == 0) + { + arg = "e.getKey()"; + type = key; + } + else + { + arg = "e.getValue()"; + type = value; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, true, iter, false, customStream); + } + out << eb; + out << eb; + } + else + { + out << nl << v << " = new " << instanceType << "();"; + out << nl << "int sz" << iterS << " = " << stream << ".readSize();"; + out << nl << "for(int i" << iterS << " = 0; i" << iterS << " < sz" << iterS << "; i" << iterS << "++)"; + out << sb; + for(int i = 0; i < 2; i++) + { + string arg; + TypePtr type; + string typeS; + if(i == 0) + { + arg = "key"; + type = key; + typeS = keyS; + } + else + { + arg = "value"; + type = value; + typeS = valueS; + } + + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(ClassDeclPtr::dynamicCast(type) || (b && b->usesClasses())) + { + string keyTypeStr = typeToObjectString(key, TypeModeIn, package); + string valueTypeStr = typeToObjectString(value, TypeModeIn, package); + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, false, iter, false, + customStream, StringList(), + "new IceInternal.DictionaryPatcher<" + keyTypeStr + ", " + valueTypeStr + + ">(" + v + ", " + typeS + ".class, key)"); + } + else + { + if(StructPtr::dynamicCast(type)) + { + out << nl << typeS << ' ' << arg << " = null;"; + } + else + { + out << nl << typeS << ' ' << arg << ';'; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, false, iter, false, customStream); + } + } + BuiltinPtr builtin = BuiltinPtr::dynamicCast(value); + if(!(builtin && builtin->usesClasses()) && !ClassDeclPtr::dynamicCast(value)) + { + out << nl << "" << v << ".put(key, value);"; + } + out << eb; + } +} + +void +Slice::JavaCompatGenerator::writeSequenceMarshalUnmarshalCode(Output& out, + const string& package, + const SequencePtr& seq, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const string& customStream, + const StringList& metaData) +{ + string stream = customStream; + if(stream.empty()) + { + stream = marshal ? "ostr" : "istr"; + } + string v = param; + + // + // If the sequence is a byte sequence, check if there's the serializable or protobuf metadata to + // get rid of these two easy cases first. + // + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + string meta; + static const string protobuf = "java:protobuf:"; + static const string serializable = "java:serializable:"; + if(seq->findMetaData(serializable, meta)) + { + if(marshal) + { + out << nl << stream << ".writeSerializable(" << v << ");"; + } + else + { + string type = typeToString(seq, TypeModeIn, package); + out << nl << v << " = (" << type << ")" << stream << ".readSerializable();"; + } + return; + } + else if(seq->findMetaData(protobuf, meta)) + { + if(marshal) + { + out << nl << "if(!" << v << ".isInitialized())"; + out << sb; + out << nl << "throw new Ice.MarshalException(\"type not fully initialized\");"; + out << eb; + out << nl << stream << ".writeByteSeq(" << v << ".toByteArray());"; + } + else + { + string type = typeToString(seq, TypeModeIn, package); + out << nl << "try"; + out << sb; + out << nl << v << " = " << type << ".parseFrom(" << stream << ".readByteSeq());"; + out << eb; + out << nl << "catch(com.google.protobuf.InvalidProtocolBufferException ex)"; + out << sb; + out << nl << "throw new Ice.MarshalException(ex);"; + out << eb; + } + return; + } + } + + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string meta; + static const string bytebuffer = "java:buffer"; + if(seq->findMetaData(bytebuffer, meta) || findMetaData(bytebuffer, metaData, meta)) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + { + if(marshal) + { + out << nl << stream << ".writeByteBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readByteBuffer();"; + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + out << nl << stream << ".writeShortBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readShortBuffer();"; + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + out << nl << stream << ".writeIntBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readIntBuffer();"; + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + out << nl << stream << ".writeLongBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readLongBuffer();"; + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + out << nl << stream << ".writeFloatBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readFloatBuffer();"; + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + out << nl << stream << ".writeDoubleBuffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readDoubleBuffer();"; + } + break; + } + case Builtin::KindBool: + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + assert(false); + break; + } + } + return; + } + } + + bool customType = false; + string instanceType; + + // + // We have to determine whether it's possible to use the + // type's generated helper class for this marshal/unmarshal + // task. Since the user may have specified a custom type in + // metadata, it's possible that the helper class is not + // compatible and therefore we'll need to generate the code + // in-line instead. + // + // Specifically, there may be "local" metadata (i.e., from + // a data member or parameter definition) that overrides the + // original type. We'll compare the mapped types with and + // without local metadata to determine whether we can use + // the helper. + // + string formalType; + customType = getSequenceTypes(seq, "", metaData, instanceType, formalType); + string origInstanceType, origFormalType; + getSequenceTypes(seq, "", StringList(), origInstanceType, origFormalType); + if((formalType != origFormalType) || (!marshal && instanceType != origInstanceType)) + { + useHelper = false; + } + + // + // If we can use the helper, it's easy. + // + if(useHelper) + { + string typeS = getAbsolute(seq, package, "", "Helper"); + if(marshal) + { + out << nl << typeS << ".write(" << stream << ", " << v << ");"; + } + else + { + out << nl << v << " = " << typeS << ".read(" << stream << ");"; + } + return; + } + + // + // Determine sequence depth. + // + int depth = 0; + TypePtr origContent = seq->type(); + SequencePtr s = SequencePtr::dynamicCast(origContent); + while(s) + { + // + // Stop if the inner sequence type has a custom, serializable or protobuf type. + // + if(hasTypeMetaData(s)) + { + break; + } + depth++; + origContent = s->type(); + s = SequencePtr::dynamicCast(origContent); + } + string origContentS = typeToString(origContent, TypeModeIn, package); + + TypePtr type = seq->type(); + + if(customType) + { + // + // Marshal/unmarshal a custom sequence type. + // + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + string typeS = getAbsolute(seq, package); + ostringstream o; + o << origContentS; + int d = depth; + while(d--) + { + o << "[]"; + } + string cont = o.str(); + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << stream << ".writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << stream << ".writeSize(" << v << ".size());"; + string typeS = typeToString(type, TypeModeIn, package); + out << nl << "for(" << typeS << " elem : " << v << ')'; + out << sb; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "elem", true, iter, false, customStream); + out << eb; + out << eb; // else + } + else + { + bool isObject = false; + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if((b && b->usesClasses()) || cl) + { + isObject = true; + } + out << nl << v << " = new " << instanceType << "();"; + out << nl << "final int len" << iter << " = " << stream << ".readAndCheckSeqSize(" << type->minWireSize() + << ");"; + out << nl << "for(int i" << iter << " = 0; i" << iter << " < len" << iter << "; i" << iter + << "++)"; + out << sb; + if(isObject) + { + // + // Add a null value to the list as a placeholder for the element. + // + out << nl << v << ".add(null);"; + ostringstream patchParams; + patchParams << "new IceInternal.ListPatcher<" << origContentS << ">(" << v << ", " << origContentS + << ".class, i" << iter << ')'; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "elem", false, iter, + false, customStream, StringList(), patchParams.str()); + } + else + { + if(StructPtr::dynamicCast(type)) + { + out << nl << cont << " elem = null;"; + } + else + { + out << nl << cont << " elem;"; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "elem", false, iter, false, customStream); + } + if(!isObject) + { + out << nl << v << ".add(elem);"; + } + out << eb; + iter++; + } + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b && b->kind() != Builtin::KindObject && + b->kind() != Builtin::KindValue && + b->kind() != Builtin::KindObjectProxy) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + if(marshal) + { + out << nl << stream << ".writeByteSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readByteSeq();"; + } + break; + } + case Builtin::KindBool: + { + if(marshal) + { + out << nl << stream << ".writeBoolSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readBoolSeq();"; + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + out << nl << stream << ".writeShortSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readShortSeq();"; + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + out << nl << stream << ".writeIntSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readIntSeq();"; + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + out << nl << stream << ".writeLongSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readLongSeq();"; + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + out << nl << stream << ".writeFloatSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readFloatSeq();"; + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + out << nl << stream << ".writeDoubleSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readDoubleSeq();"; + } + break; + } + case Builtin::KindString: + { + if(marshal) + { + out << nl << stream << ".writeStringSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readStringSeq();"; + } + break; + } + case Builtin::KindValue: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + } + else + { + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << stream << ".writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << stream << ".writeSize(" << v << ".length);"; + out << nl << "for(int i" << iter << " = 0; i" << iter << " < " << v << ".length; i" << iter + << "++)"; + out << sb; + ostringstream o; + o << v << "[i" << iter << "]"; + iter++; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), true, iter, false, customStream); + out << eb; + out << eb; + } + else + { + bool isObject = false; + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(origContent); + if((b && b->usesClasses()) || cl) + { + isObject = true; + } + out << nl << "final int len" << iter << " = " << stream << ".readAndCheckSeqSize(" + << type->minWireSize() << ");"; + // + // We cannot allocate an array of a generic type, such as + // + // arr = new Map<String, String>[sz]; + // + // Attempting to compile this code results in a "generic array creation" error + // message. This problem can occur when the sequence's element type is a + // dictionary, or when the element type is a nested sequence that uses a custom + // mapping. + // + // The solution is to rewrite the code as follows: + // + // arr = (Map<String, String>[])new Map[sz]; + // + // Unfortunately, this produces an unchecked warning during compilation. + // + // A simple test is to look for a "<" character in the content type, which + // indicates the use of a generic type. + // + string::size_type pos = origContentS.find('<'); + if(pos != string::npos) + { + string nonGenericType = origContentS.substr(0, pos); + out << nl << v << " = (" << origContentS << "[]"; + int d = depth; + while(d--) + { + out << "[]"; + } + out << ")new " << nonGenericType << "[len" << iter << "]"; + } + else + { + out << nl << v << " = new " << origContentS << "[len" << iter << "]"; + } + int d = depth; + while(d--) + { + out << "[]"; + } + out << ';'; + out << nl << "for(int i" << iter << " = 0; i" << iter << " < len" << iter << "; i" << iter + << "++)"; + out << sb; + ostringstream o; + o << v << "[i" << iter << "]"; + ostringstream patchParams; + if(isObject) + { + patchParams << "new IceInternal.SequencePatcher(" << v << ", " << origContentS + << ".class, i" << iter << ')'; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), false, iter, + false, customStream, StringList(), patchParams.str()); + } + else + { + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), false, + iter, false, customStream); + } + out << eb; + iter++; + } + } + } +} + +bool +Slice::JavaCompatGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value) +{ + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) + { + if(q->find(prefix) == 0) + { + value = *q; + return true; + } + } + + return false; +} + +bool +Slice::JavaCompatGenerator::getTypeMetaData(const StringList& metaData, string& instanceType, string& formalType) +{ + // + // Extract the instance type and an optional formal type. + // The correct syntax is "java:type:instance-type[:formal-type]". + // + static const string prefix = "java:type:"; + string directive; + if(findMetaData(prefix, metaData, directive)) + { + string::size_type pos = directive.find(':', prefix.size()); + if(pos != string::npos) + { + instanceType = directive.substr(prefix.size(), pos - prefix.size()); + formalType = directive.substr(pos + 1); + } + else + { + instanceType = directive.substr(prefix.size()); + formalType.clear(); + } + return true; + } + + return false; +} + +bool +Slice::JavaCompatGenerator::hasTypeMetaData(const TypePtr& type, const StringList& localMetaData) +{ + ContainedPtr cont = ContainedPtr::dynamicCast(type); + if(cont) + { + static const string prefix = "java:type:"; + string directive; + + if(findMetaData(prefix, localMetaData, directive)) + { + return true; + } + + StringList metaData = cont->getMetaData(); + + if(findMetaData(prefix, metaData, directive)) + { + return true; + } + + if(findMetaData("java:protobuf:", metaData, directive) || + findMetaData("java:serializable:", metaData, directive)) + { + SequencePtr seq = SequencePtr::dynamicCast(cont); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + return true; + } + } + } + + if(findMetaData("java:buffer", localMetaData, directive)) + { + SequencePtr seq = SequencePtr::dynamicCast(cont); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + return true; + } + } + } + } + + return false; +} + +bool +Slice::JavaCompatGenerator::getDictionaryTypes(const DictionaryPtr& dict, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType) const +{ + // + // Get the types of the key and value. + // + string keyTypeStr = typeToObjectString(dict->keyType(), TypeModeIn, package); + string valueTypeStr = typeToObjectString(dict->valueType(), TypeModeIn, package); + + // + // Collect metadata for a custom type. + // + if(getTypeMetaData(metaData, instanceType, formalType) || + getTypeMetaData(dict->getMetaData(), instanceType, formalType)) + { + assert(!instanceType.empty()); + if(formalType.empty()) + { + formalType = "java.util.Map<" + keyTypeStr + ", " + valueTypeStr + ">"; + } + return true; + } + + // + // Return a default type for the platform. + // + instanceType = "java.util.HashMap<" + keyTypeStr + ", " + valueTypeStr + ">"; + formalType = "java.util.Map<" + keyTypeStr + ", " + valueTypeStr + ">"; + return false; +} + +bool +Slice::JavaCompatGenerator::getSequenceTypes(const SequencePtr& seq, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType) const +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin) + { + if(builtin->kind() == Builtin::KindByte) + { + string prefix = "java:serializable:"; + string meta; + if(seq->findMetaData(prefix, meta)) + { + instanceType = formalType = meta.substr(prefix.size()); + return true; + } + prefix = "java:protobuf:"; + if(seq->findMetaData(prefix, meta)) + { + instanceType = formalType = meta.substr(prefix.size()); + return true; + } + } + + if((builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string prefix = "java:buffer"; + string meta; + string ignore; + if(seq->findMetaData(prefix, meta) || findMetaData(prefix, metaData, ignore)) + { + instanceType = formalType = typeToBufferString(seq->type()); + return true; + } + } + } + + // + // Collect metadata for a custom type. + // + if(getTypeMetaData(metaData, instanceType, formalType) || + getTypeMetaData(seq->getMetaData(), instanceType, formalType)) + { + assert(!instanceType.empty()); + if(formalType.empty()) + { + formalType = "java.util.List<" + typeToObjectString(seq->type(), TypeModeIn, package) + ">"; + } + return true; + } + + // + // The default mapping is a native array. + // + instanceType = formalType = typeToString(seq->type(), TypeModeIn, package, metaData) + "[]"; + return false; +} + +bool +Slice::JavaCompatGenerator::sequenceHasHolder(const SequencePtr& p) const +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + string prefix = "java:serializable:"; + string meta; + if(p->findMetaData(prefix, meta)) + { + return false; + } + prefix = "java:protobuf:"; + if(p->findMetaData(prefix, meta)) + { + return false; + } + } + + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string meta; + string prefix = "java:buffer"; + if(p->findMetaData(prefix, meta)) + { + return false; + } + } + + return true; +} + + +JavaOutput* +Slice::JavaCompatGenerator::createOutput() +{ + return new JavaOutput; +} + +void +Slice::JavaCompatGenerator::validateMetaData(const UnitPtr& u) +{ + MetaDataVisitor visitor; + u->visit(&visitor, true); +} + +const string Slice::JavaGenerator::_getSetMetaData = "java:getset"; + +Slice::JavaGenerator::JavaGenerator(const string& dir) : + _dir(dir), + _out(0) +{ +} + +Slice::JavaGenerator::~JavaGenerator() +{ + // If open throws an exception other generators could be left open + // during the stack unwind. + if(_out != 0) + { + close(); + } + assert(_out == 0); +} + +void +Slice::JavaGenerator::open(const string& absolute, const string& file) +{ + assert(_out == 0); + + JavaOutput* out = createOutput(); + try + { + out->openClass(absolute, _dir, file); + } + catch(const FileException&) + { + delete out; + throw; + } + _out = out; +} + +void +Slice::JavaGenerator::close() +{ + assert(_out != 0); + *_out << nl; + delete _out; + _out = 0; +} + +Output& +Slice::JavaGenerator::output() const +{ + assert(_out != 0); + return *_out; +} + +// +// If the passed name is a scoped name, return the identical scoped name, +// but with all components that are Java keywords replaced by +// their "_"-prefixed version; otherwise, if the passed name is +// not scoped, but a Java keyword, return the "_"-prefixed name; +// otherwise, return the name unchanged. +// +string +Slice::JavaGenerator::fixKwd(const string& name) const +{ + if(name.empty()) + { + return name; + } + if(name[0] != ':') + { + return lookupKwd(name); + } + StringList ids = splitScopedName(name); + transform(ids.begin(), ids.end(), ids.begin(), ptr_fun(lookupKwd)); + stringstream result; + for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i) + { + result << "::" + *i; + } + return result.str(); +} + +string +Slice::JavaGenerator::convertScopedName(const string& scoped, const string& prefix, const string& suffix) const +{ + string result; + string::size_type start = 0; + string fscoped = fixKwd(scoped); + + // + // Skip leading "::" + // + if(fscoped[start] == ':') + { + assert(fscoped[start + 1] == ':'); + start += 2; + } + + // + // Convert all occurrences of "::" to "." + // + string::size_type pos; + do + { + pos = fscoped.find(':', start); + string fix; + if(pos == string::npos) + { + string s = fscoped.substr(start); + if(!s.empty()) + { + fix = prefix + fixKwd(s) + suffix; + } + } + else + { + assert(fscoped[pos + 1] == ':'); + fix = fixKwd(fscoped.substr(start, pos - start)); + start = pos + 2; + } + + if(!result.empty() && !fix.empty()) + { + result += "."; + } + result += fix; + } + while(pos != string::npos); + + return result; +} + +string +Slice::JavaGenerator::getPackagePrefix(const ContainedPtr& cont) const +{ + UnitPtr unit = cont->container()->unit(); + string file = cont->file(); + assert(!file.empty()); + + map<string, string>::const_iterator p = _filePackagePrefix.find(file); + if(p != _filePackagePrefix.end()) + { + return p->second; + } + + static const string prefix = "java:package:"; + DefinitionContextPtr dc = unit->findDefinitionContext(file); + assert(dc); + string q = dc->findMetaData(prefix); + if(!q.empty()) + { + q = q.substr(prefix.size()); + } + _filePackagePrefix[file] = q; + return q; +} + +string +Slice::JavaGenerator::getPackage(const ContainedPtr& cont) const +{ + string scope = convertScopedName(cont->scope()); + string prefix = getPackagePrefix(cont); + if(!prefix.empty()) + { + if(!scope.empty()) + { + return prefix + "." + scope; + } + else + { + return prefix; + } + } + + return scope; +} + +string +Slice::JavaGenerator::getAbsolute(const ContainedPtr& cont, + const string& package, + const string& prefix, + const string& suffix) const +{ + string name = cont->name(); + if(prefix == "" && suffix == "") + { + name = fixKwd(name); + } + string contPkg = getPackage(cont); + if(contPkg == package) + { + return prefix + name + suffix; + } + else if(!contPkg.empty()) + { + return contPkg + "." + prefix + name + suffix; + } + else + { + return prefix + name + suffix; + } +} + +string +Slice::JavaGenerator::getStaticId(const TypePtr& type, const string& package) const +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + + assert((b && b->usesClasses()) || cl); + + if(b && b->kind() == Builtin::KindObject) + { + return "com.zeroc.Ice.Object.ice_staticId()"; + } + else if(b && b->kind() == Builtin::KindValue) + { + return "com.zeroc.Ice.Value.ice_staticId()"; + } + else + { + return getAbsolute(cl, package) + ".ice_staticId()"; + } +} + +bool +Slice::JavaGenerator::useOptionalMapping(const OperationPtr& p) +{ + // + // The "java:optional" metadata can be applied to an operation or its + // interface to force the mapping to use the Optional types. + // + // Without the tag, parameters use the normal (non-optional) mapping. + // + static const string tag = "java:optional"; + + ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container()); + assert(cl); + + return p->hasMetaData(tag) || cl->hasMetaData(tag); +} + +string +Slice::JavaGenerator::getOptionalFormat(const TypePtr& type) +{ + const string prefix = "com.zeroc.Ice.OptionalFormat."; + + BuiltinPtr bp = BuiltinPtr::dynamicCast(type); + if(bp) + { + switch(bp->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + { + return prefix + "F1"; + } + case Builtin::KindShort: + { + return prefix + "F2"; + } + case Builtin::KindInt: + case Builtin::KindFloat: + { + return prefix + "F4"; + } + case Builtin::KindLong: + case Builtin::KindDouble: + { + return prefix + "F8"; + } + case Builtin::KindString: + { + return prefix + "VSize"; + } + case Builtin::KindObject: + { + return prefix + "Class"; + } + case Builtin::KindObjectProxy: + { + return prefix + "FSize"; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + case Builtin::KindValue: + { + return prefix + "Class"; + } + } + } + + if(EnumPtr::dynamicCast(type)) + { + return prefix + "Size"; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + return seq->type()->isVariableLength() ? prefix + "FSize" : prefix + "VSize"; + } + + DictionaryPtr d = DictionaryPtr::dynamicCast(type); + if(d) + { + return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ? + prefix + "FSize" : prefix + "VSize"; + } + + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + return st->isVariableLength() ? prefix + "FSize" : prefix + "VSize"; + } + + if(ProxyPtr::dynamicCast(type)) + { + return prefix + "FSize"; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + assert(cl); + return prefix + "Class"; +} + +string +Slice::JavaGenerator::typeToString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal, + bool optional, + bool local) const +{ + static const char* builtinTable[] = + { + "byte", + "boolean", + "short", + "int", + "long", + "float", + "double", + "String", + "com.zeroc.Ice.Value", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + static const char* builtinLocalTable[] = + { + "byte", + "boolean", + "short", + "int", + "long", + "float", + "double", + "String", + "com.zeroc.Ice.Object", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + static const char* builtinOptionalTable[] = + { + "java.util.Optional<java.lang.Byte>", + "java.util.Optional<java.lang.Boolean>", + "java.util.Optional<java.lang.Short>", + "java.util.OptionalInt", + "java.util.OptionalLong", + "java.util.Optional<java.lang.Float>", + "java.util.OptionalDouble", + "???", + "???", + "???", + "???", + "???" + }; + + if(!type) + { + assert(mode == TypeModeReturn); + return "void"; + } + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + if(optional) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + { + return builtinOptionalTable[builtin->kind()]; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + break; + } + } + } + else + { + return local ? builtinLocalTable[builtin->kind()] : builtinTable[builtin->kind()]; + } + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + + if(optional) + { + return "java.util.Optional<" + typeToObjectString(type, mode, package, metaData, formal, local) + ">"; + } + + if(cl) + { + if(cl->isInterface() && !local) + { + return "com.zeroc.Ice.Value"; + } + else + { + return getAbsolute(cl, package); + } + } + + ProxyPtr proxy = ProxyPtr::dynamicCast(type); + if(proxy) + { + ClassDefPtr def = proxy->_class()->definition(); + assert(def); + if(def->isAbstract()) + { + return getAbsolute(proxy->_class(), package, "", "Prx"); + } + else + { + return "com.zeroc.Ice.ObjectPrx"; + } + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + string instanceType, formalType; + getDictionaryTypes(dict, package, metaData, instanceType, formalType, local); + return formal ? formalType : instanceType; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + string instanceType, formalType; + getSequenceTypes(seq, package, metaData, instanceType, formalType, local); + return formal ? formalType : instanceType; + } + + ContainedPtr contained = ContainedPtr::dynamicCast(type); + if(contained) + { + if(mode == TypeModeOut) + { + return getAbsolute(contained, package, "", "Holder"); + } + else + { + return getAbsolute(contained, package); + } + } + + return "???"; +} + +string +Slice::JavaGenerator::typeToObjectString(const TypePtr& type, + TypeMode mode, + const string& package, + const StringList& metaData, + bool formal, + bool local) const +{ + static const char* builtinTable[] = + { + "java.lang.Byte", + "java.lang.Boolean", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + "java.lang.String", + "com.zeroc.Ice.Value", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + static const char* builtinLocalTable[] = + { + "java.lang.Byte", + "java.lang.Boolean", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + "java.lang.String", + "com.zeroc.Ice.Object", + "com.zeroc.Ice.ObjectPrx", + "java.lang.Object", + "com.zeroc.Ice.Value" + }; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin && mode != TypeModeOut) + { + return local ? builtinLocalTable[builtin->kind()] : builtinTable[builtin->kind()]; + } + + return typeToString(type, mode, package, metaData, formal, false, local); +} + +void +Slice::JavaGenerator::writeMarshalUnmarshalCode(Output& out, + const string& package, + const TypePtr& type, + OptionalMode mode, + bool optionalMapping, + int tag, + const string& param, + bool marshal, + int& iter, + const string& customStream, + const StringList& metaData, + const string& patchParams) +{ + string stream = customStream; + if(stream.empty()) + { + stream = marshal ? "ostr" : "istr"; + } + + const bool optionalParam = mode == OptionalInParam || mode == OptionalOutParam || mode == OptionalReturnParam; + string typeS = typeToString(type, TypeModeIn, package, metaData); + + assert(!marshal || mode != OptionalMember); // Only support OptionalMember for un-marshaling + + static const char* builtinTable[] = + { + "Byte", + "Bool", + "Short", + "Int", + "Long", + "Float", + "Double", + "String", + "???", + "???", + "???" + }; + + const BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindByte: + case Builtin::KindBool: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + case Builtin::KindFloat: + case Builtin::KindDouble: + case Builtin::KindString: + { + string s = builtinTable[builtin->kind()]; + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".write" << s << "(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".write" << s << "(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".read" << s << "(" << tag << ");"; + } + else + { + out << nl << param << " = " << stream << ".read" << s << "();"; + } + } + break; + } + case Builtin::KindObject: + case Builtin::KindValue: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeValue(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeValue(" << param << ");"; + } + } + else + { + assert(!patchParams.empty()); + if(optionalParam) + { + out << nl << stream << ".readValue(" << tag << ", " << patchParams << ");"; + } + else + { + out << nl << stream << ".readValue(" << patchParams << ");"; + } + } + break; + } + case Builtin::KindObjectProxy: + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeProxy(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeProxy(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readProxy(" << tag << ");"; + } + else if(mode == OptionalMember) + { + out << nl << stream << ".skip(4);"; + out << nl << param << " = " << stream << ".readProxy();"; + } + else + { + out << nl << param << " = " << stream << ".readProxy();"; + } + } + break; + } + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + return; + } + + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeProxy(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeProxy(" << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << stream << ".readProxy(" << tag << ", " << typeS << "::uncheckedCast);"; + } + else if(mode == OptionalMember) + { + out << nl << stream << ".skip(4);"; + out << nl << param << " = " << typeS << ".uncheckedCast(" << stream << ".readProxy());"; + } + else + { + out << nl << param << " = " << typeS << ".uncheckedCast(" << stream << ".readProxy());"; + } + } + return; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + if(marshal) + { + if(optionalParam) + { + out << nl << stream << ".writeValue(" << tag << ", " << param << ");"; + } + else + { + out << nl << stream << ".writeValue(" << param << ");"; + } + } + else + { + assert(!patchParams.empty()); + if(optionalParam) + { + out << nl << stream << ".readValue(" << tag << ", " << patchParams << ");"; + } + else + { + out << nl << stream << ".readValue(" << patchParams << ");"; + } + } + return; + } + + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + if(dict) + { + if(optionalParam || mode == OptionalMember) + { + string instanceType, formalType, origInstanceType, origFormalType; + getDictionaryTypes(dict, "", metaData, instanceType, formalType, false); + getDictionaryTypes(dict, "", StringList(), origInstanceType, origFormalType, false); + if(formalType == origFormalType && (marshal || instanceType == origInstanceType)) + { + // + // If we can use the helper, it's easy. + // + string helper = getAbsolute(dict, package, "", "Helper"); + if(marshal) + { + out << nl << helper << ".write" << spar << stream << tag << param << epar << ";"; + return; + } + else if(mode != OptionalMember) + { + out << nl << param << " = " << helper << ".read" << spar << stream << tag << epar << ";"; + return; + } + } + + TypePtr keyType = dict->keyType(); + TypePtr valueType = dict->valueType(); + if(marshal) + { + if(optionalParam) + { + out << nl; + if(optionalMapping) + { + out << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + } + else + { + out << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + } + out << sb; + } + + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + string d = optionalParam && optionalMapping ? param + ".get()" : param; + out << nl << "int pos = " << stream << ".startSize();"; + writeDictionaryMarshalUnmarshalCode(out, package, dict, d, marshal, iter, true, customStream, metaData); + out << nl << stream << ".endSize(pos);"; + } + else + { + const size_t sz = keyType->minWireSize() + valueType->minWireSize(); + string d = optionalParam && optionalMapping ? param + ".get()" : param; + out << nl << "final int optSize = " << d << " == null ? 0 : " << d << ".size();"; + out << nl << stream + << ".writeSize(optSize > 254 ? optSize * " << sz << " + 5 : optSize * " << sz << " + 1);"; + writeDictionaryMarshalUnmarshalCode(out, package, dict, d, marshal, iter, true, customStream, metaData); + } + + if(optionalParam) + { + out << eb; + } + } + else + { + string d = optionalParam ? "optDict" : param; + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ' ' << d << ';'; + } + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else + { + out << nl << stream << ".skipSize();"; + } + writeDictionaryMarshalUnmarshalCode(out, package, dict, d, marshal, iter, true, customStream, metaData); + if(optionalParam) + { + out << nl << param << " = java.util.Optional.of(" << d << ");"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } + } + } + else + { + writeDictionaryMarshalUnmarshalCode(out, package, dict, param, marshal, iter, true, customStream, metaData); + } + return; + } + + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + if(optionalParam || mode == OptionalMember) + { + string ignore; + TypePtr elemType = seq->type(); + BuiltinPtr eltBltin = BuiltinPtr::dynamicCast(elemType); + if(!hasTypeMetaData(seq, metaData) && eltBltin && eltBltin->kind() < Builtin::KindObject) + { + string bs = builtinTable[eltBltin->kind()]; + if(marshal) + { + out << nl << stream << ".write" << bs << "Seq(" << tag << ", " << param << ");"; + return; + } + else if(mode != OptionalMember) + { + out << nl << param << " = " << stream << ".read" << bs << "Seq(" << tag << ");"; + return; + } + } + else if(findMetaData("java:serializable", seq->getMetaData(), ignore)) + { + if(marshal) + { + out << nl << stream << ".writeSerializable" << spar << tag << param << epar << ";"; + return; + } + else if(mode != OptionalMember) + { + out << nl << param << " = " << stream << ".readSerializable" << spar << tag << typeS + ".class" << epar << ";"; + return; + } + } + else if(!hasTypeMetaData(seq, metaData) || + findMetaData("java:type", seq->getMetaData(), ignore) || + findMetaData("java:type", metaData, ignore)) + { + string instanceType, formalType, origInstanceType, origFormalType; + getSequenceTypes(seq, "", metaData, instanceType, formalType, false); + getSequenceTypes(seq, "", StringList(), origInstanceType, origFormalType, false); + if(formalType == origFormalType && (marshal || instanceType == origInstanceType)) + { + string helper = getAbsolute(seq, package, "", "Helper"); + if(marshal) + { + out << nl << helper << ".write" << spar << stream << tag << param << epar << ";"; + return; + } + else if(mode != OptionalMember) + { + out << nl << param << " = " << helper << ".read" << spar << stream << tag << epar << ";"; + return; + } + } + } + + if(marshal) + { + if(optionalParam) + { + out << nl; + if(optionalMapping) + { + out << "if(" << param << " != null && " << param << ".isPresent() && " << stream + << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + } + else + { + out << "if(" << stream << ".writeOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + } + out << sb; + } + + if(elemType->isVariableLength()) + { + string s = optionalParam && optionalMapping ? param + ".get()" : param; + out << nl << "int pos = " << stream << ".startSize();"; + writeSequenceMarshalUnmarshalCode(out, package, seq, s, true, iter, true, customStream, metaData); + out << nl << stream << ".endSize(pos);"; + } + else + { + const size_t sz = elemType->minWireSize(); + string s = optionalParam && optionalMapping ? param + ".get()" : param; + if(sz > 1) + { + string ignore; + out << nl << "final int optSize = " << s << " == null ? 0 : "; + if(findMetaData("java:buffer", seq->getMetaData(), ignore) || + findMetaData("java:buffer", metaData, ignore)) + { + out << s << ".remaining() / " << sz << ";"; + } + else if(hasTypeMetaData(seq, metaData)) + { + out << s << ".size();"; + } + else + { + out << s << ".length;"; + } + out << nl << stream << ".writeSize(optSize > 254 ? optSize * " << sz + << " + 5 : optSize * " << sz << " + 1);"; + } + writeSequenceMarshalUnmarshalCode(out, package, seq, s, true, iter, true, customStream, metaData); + } + + if(optionalParam) + { + out << eb; + } + } + else + { + const size_t sz = elemType->minWireSize(); + string s = optionalParam ? "optSeq" : param; + if(optionalParam) + { + out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(type) << "))"; + out << sb; + out << nl << typeS << ' ' << s << ';'; + } + if(elemType->isVariableLength()) + { + out << nl << stream << ".skip(4);"; + } + else if(sz > 1) + { + out << nl << stream << ".skipSize();"; + } + writeSequenceMarshalUnmarshalCode(out, package, seq, s, false, iter, true, customStream, metaData); + if(optionalParam) + { + out << nl << param << " = java.util.Optional.of(" << s << ");"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << param << " = java.util.Optional.empty();"; + out << eb; + } + } + } + else + { + writeSequenceMarshalUnmarshalCode(out, package, seq, param, marshal, iter, true, customStream, metaData); + } + return; + } + + ConstructedPtr constructed = ConstructedPtr::dynamicCast(type); + StructPtr st = StructPtr::dynamicCast(type); + assert(constructed); + if(marshal) + { + if(optionalParam) + { + out << nl << typeS << ".ice_write(" << stream << ", " << tag << ", " << param << ");"; + } + else + { + out << nl << typeS << ".ice_write(" << stream << ", " << param << ");"; + } + } + else + { + if(optionalParam) + { + out << nl << param << " = " << typeS << ".ice_read(" << stream << ", " << tag << ");"; + } + else if(mode == OptionalMember && st) + { + out << nl << stream << (st->isVariableLength() ? ".skip(4);" : ".skipSize();"); + out << nl << param << " = " << typeS << ".ice_read(" << stream << ");"; + } + else + { + out << nl << param << " = " << typeS << ".ice_read(" << stream << ");"; + } + } +} + +void +Slice::JavaGenerator::writeDictionaryMarshalUnmarshalCode(Output& out, + const string& package, + const DictionaryPtr& dict, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const string& customStream, + const StringList& metaData) +{ + string stream = customStream; + if(stream.empty()) + { + stream = marshal ? "ostr" : "istr"; + } + + string v = param; + + // + // We have to determine whether it's possible to use the + // type's generated helper class for this marshal/unmarshal + // task. Since the user may have specified a custom type in + // metadata, it's possible that the helper class is not + // compatible and therefore we'll need to generate the code + // in-line instead. + // + // Specifically, there may be "local" metadata (i.e., from + // a data member or parameter definition) that overrides the + // original type. We'll compare the mapped types with and + // without local metadata to determine whether we can use + // the helper. + // + string instanceType, formalType, origInstanceType, origFormalType; + getDictionaryTypes(dict, "", metaData, instanceType, formalType, false); + getDictionaryTypes(dict, "", StringList(), origInstanceType, origFormalType, false); + if(useHelper && formalType == origFormalType && (marshal || instanceType == origInstanceType)) + { + // + // If we can use the helper, it's easy. + // + string helper = getAbsolute(dict, package, "", "Helper"); + if(marshal) + { + out << nl << helper << ".write" << spar << stream << v << epar << ";"; + } + else + { + out << nl << v << " = " << helper << ".read" << spar << stream << epar << ";"; + } + return; + } + + TypePtr key = dict->keyType(); + TypePtr value = dict->valueType(); + + string keyS = typeToString(key, TypeModeIn, package); + string valueS = typeToString(value, TypeModeIn, package); + + ostringstream o; + o << iter; + string iterS = o.str(); + iter++; + + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << "ostr.writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "ostr.writeSize(" << v << ".size());"; + string keyObjectS = typeToObjectString(key, TypeModeIn, package); + string valueObjectS = typeToObjectString(value, TypeModeIn, package); + out << nl; + out << "for(java.util.Map.Entry<" << keyObjectS << ", " << valueObjectS << "> e : " << v << ".entrySet())"; + out << sb; + for(int i = 0; i < 2; i++) + { + string arg; + TypePtr type; + if(i == 0) + { + arg = "e.getKey()"; + type = key; + } + else + { + arg = "e.getValue()"; + type = value; + } + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, arg, true, iter, customStream); + } + out << eb; + out << eb; + } + else + { + out << nl << v << " = new " << instanceType << "();"; + out << nl << "int sz" << iterS << " = " << stream << ".readSize();"; + out << nl << "for(int i" << iterS << " = 0; i" << iterS << " < sz" << iterS << "; i" << iterS << "++)"; + out << sb; + + BuiltinPtr b = BuiltinPtr::dynamicCast(value); + if(ClassDeclPtr::dynamicCast(value) || (b && b->usesClasses())) + { + out << nl << "final " << keyS << " key;"; + writeMarshalUnmarshalCode(out, package, key, OptionalNone, false, 0, "key", false, iter, customStream); + + string valueS = typeToObjectString(value, TypeModeIn, package); + ostringstream patchParams; + patchParams << "value -> " << v << ".put(key, value), " << valueS << ".class"; + writeMarshalUnmarshalCode(out, package, value, OptionalNone, false, 0, "value", false, iter, customStream, + StringList(), patchParams.str()); + } + else + { + out << nl << keyS << " key;"; + writeMarshalUnmarshalCode(out, package, key, OptionalNone, false, 0, "key", false, iter, customStream); + + out << nl << valueS << " value;"; + writeMarshalUnmarshalCode(out, package, value, OptionalNone, false, 0, "value", false, iter, customStream); + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(value); + if(!(builtin && builtin->usesClasses()) && !ClassDeclPtr::dynamicCast(value)) + { + out << nl << "" << v << ".put(key, value);"; + } + } + out << eb; + } +} + +void +Slice::JavaGenerator::writeSequenceMarshalUnmarshalCode(Output& out, + const string& package, + const SequencePtr& seq, + const string& param, + bool marshal, + int& iter, + bool useHelper, + const string& customStream, + const StringList& metaData) +{ + string stream = customStream; + if(stream.empty()) + { + stream = marshal ? "ostr" : "istr"; + } + + string typeS = typeToString(seq, TypeModeIn, package); + string v = param; + + // + // If the sequence is a byte sequence, check if there's the serializable or protobuf metadata to + // get rid of these two easy cases first. + // + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + string meta; + static const string protobuf = "java:protobuf:"; + static const string serializable = "java:serializable:"; + if(seq->findMetaData(serializable, meta)) + { + if(marshal) + { + out << nl << stream << ".writeSerializable(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readSerializable(" << typeS << ".class);"; + } + return; + } + else if(seq->findMetaData(protobuf, meta)) + { + if(marshal) + { + out << nl << "if(!" << v << ".isInitialized())"; + out << sb; + out << nl << "throw new com.zeroc.Ice.MarshalException(\"type not fully initialized\");"; + out << eb; + out << nl << stream << ".writeByteSeq(" << v << ".toByteArray());"; + } + else + { + string type = typeToString(seq, TypeModeIn, package); + out << nl << "try"; + out << sb; + out << nl << v << " = " << typeS << ".parseFrom(" << stream << ".readByteSeq());"; + out << eb; + out << nl << "catch(com.google.protobuf.InvalidProtocolBufferException ex)"; + out << sb; + out << nl << "throw new com.zeroc.Ice.MarshalException(ex);"; + out << eb; + } + return; + } + } + + static const char* builtinTable[] = + { + "Byte", + "Bool", + "Short", + "Int", + "Long", + "Float", + "Double", + "String" + }; + + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string meta; + static const string bytebuffer = "java:buffer"; + if(seq->findMetaData(bytebuffer, meta) || findMetaData(bytebuffer, metaData, meta)) + { + if(marshal) + { + out << nl << stream << ".write" << builtinTable[builtin->kind()] << "Buffer(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".read" << builtinTable[builtin->kind()] << "Buffer();"; + } + return; + } + } + + if(!hasTypeMetaData(seq, metaData) && builtin && builtin->kind() <= Builtin::KindString) + { + if(marshal) + { + out << nl << stream << ".write" << builtinTable[builtin->kind()] << "Seq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".read" << builtinTable[builtin->kind()] << "Seq();"; + } + return; + } + + // + // We have to determine whether it's possible to use the + // type's generated helper class for this marshal/unmarshal + // task. Since the user may have specified a custom type in + // metadata, it's possible that the helper class is not + // compatible and therefore we'll need to generate the code + // in-line instead. + // + // Specifically, there may be "local" metadata (i.e., from + // a data member or parameter definition) that overrides the + // original type. We'll compare the mapped types with and + // without local metadata to determine whether we can use + // the helper. + // + string instanceType, formalType, origInstanceType, origFormalType; + bool customType = getSequenceTypes(seq, "", metaData, instanceType, formalType, false); + getSequenceTypes(seq, "", StringList(), origInstanceType, origFormalType, false); + if(useHelper && formalType == origFormalType && (marshal || instanceType == origInstanceType)) + { + // + // If we can use the helper, it's easy. + // + string helper = getAbsolute(seq, package, "", "Helper"); + if(marshal) + { + out << nl << helper << ".write" << spar << stream << v << epar << ";"; + } + else + { + out << nl << v << " = " << helper << ".read" << spar << stream << epar << ";"; + } + return; + } + + // + // Determine sequence depth. + // + int depth = 0; + TypePtr origContent = seq->type(); + SequencePtr s = SequencePtr::dynamicCast(origContent); + while(s) + { + // + // Stop if the inner sequence type has a custom, serializable or protobuf type. + // + if(hasTypeMetaData(s)) + { + break; + } + depth++; + origContent = s->type(); + s = SequencePtr::dynamicCast(origContent); + } + string origContentS = typeToString(origContent, TypeModeIn, package); + + TypePtr type = seq->type(); + + if(customType) + { + // + // Marshal/unmarshal a custom sequence type. + // + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + string typeS = getAbsolute(seq, package); + ostringstream o; + o << origContentS; + int d = depth; + while(d--) + { + o << "[]"; + } + string cont = o.str(); + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << stream << ".writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << stream << ".writeSize(" << v << ".size());"; + string typeS = typeToString(type, TypeModeIn, package); + out << nl << "for(" << typeS << " elem : " << v << ')'; + out << sb; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "elem", true, iter, customStream); + out << eb; + out << eb; // else + } + else + { + bool isObject = false; + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if((b && b->usesClasses()) || cl) + { + isObject = true; + } + out << nl << v << " = new " << instanceType << "();"; + out << nl << "final int len" << iter << " = " << stream << ".readAndCheckSeqSize(" << type->minWireSize() + << ");"; + out << nl << "for(int i" << iter << " = 0; i" << iter << " < len" << iter << "; i" << iter << "++)"; + out << sb; + if(isObject) + { + // + // Add a null value to the list as a placeholder for the element. + // + out << nl << v << ".add(null);"; + ostringstream patchParams; + out << nl << "final int fi" << iter << " = i" << iter << ";"; + patchParams << "value -> " << v << ".set(fi" << iter << ", value), " << origContentS << ".class"; + + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "elem", false, iter, + customStream, StringList(), patchParams.str()); + } + else + { + out << nl << cont << " elem;"; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, "elem", false, iter, customStream); + out << nl << v << ".add(elem);"; + } + out << eb; + iter++; + } + } + else + { + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b && b->kind() != Builtin::KindObject && + b->kind() != Builtin::KindValue && + b->kind() != Builtin::KindObjectProxy) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + if(marshal) + { + out << nl << stream << ".writeByteSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readByteSeq();"; + } + break; + } + case Builtin::KindBool: + { + if(marshal) + { + out << nl << stream << ".writeBoolSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readBoolSeq();"; + } + break; + } + case Builtin::KindShort: + { + if(marshal) + { + out << nl << stream << ".writeShortSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readShortSeq();"; + } + break; + } + case Builtin::KindInt: + { + if(marshal) + { + out << nl << stream << ".writeIntSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readIntSeq();"; + } + break; + } + case Builtin::KindLong: + { + if(marshal) + { + out << nl << stream << ".writeLongSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readLongSeq();"; + } + break; + } + case Builtin::KindFloat: + { + if(marshal) + { + out << nl << stream << ".writeFloatSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readFloatSeq();"; + } + break; + } + case Builtin::KindDouble: + { + if(marshal) + { + out << nl << stream << ".writeDoubleSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readDoubleSeq();"; + } + break; + } + case Builtin::KindString: + { + if(marshal) + { + out << nl << stream << ".writeStringSeq(" << v << ");"; + } + else + { + out << nl << v << " = " << stream << ".readStringSeq();"; + } + break; + } + case Builtin::KindValue: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + assert(false); + break; + } + } + } + else + { + if(marshal) + { + out << nl << "if(" << v << " == null)"; + out << sb; + out << nl << stream << ".writeSize(0);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << stream << ".writeSize(" << v << ".length);"; + out << nl << "for(int i" << iter << " = 0; i" << iter << " < " << v << ".length; i" << iter + << "++)"; + out << sb; + ostringstream o; + o << v << "[i" << iter << "]"; + iter++; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), true, iter, customStream); + out << eb; + out << eb; + } + else + { + bool isObject = false; + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(origContent); + if((b && b->usesClasses()) || cl) + { + isObject = true; + } + out << nl << "final int len" << iter << " = " << stream << ".readAndCheckSeqSize(" + << type->minWireSize() << ");"; + // + // We cannot allocate an array of a generic type, such as + // + // arr = new Map<String, String>[sz]; + // + // Attempting to compile this code results in a "generic array creation" error + // message. This problem can occur when the sequence's element type is a + // dictionary, or when the element type is a nested sequence that uses a custom + // mapping. + // + // The solution is to rewrite the code as follows: + // + // arr = (Map<String, String>[])new Map[sz]; + // + // Unfortunately, this produces an unchecked warning during compilation. + // + // A simple test is to look for a "<" character in the content type, which + // indicates the use of a generic type. + // + string::size_type pos = origContentS.find('<'); + if(pos != string::npos) + { + string nonGenericType = origContentS.substr(0, pos); + out << nl << v << " = (" << origContentS << "[]"; + int d = depth; + while(d--) + { + out << "[]"; + } + out << ")new " << nonGenericType << "[len" << iter << "]"; + } + else + { + out << nl << v << " = new " << origContentS << "[len" << iter << "]"; + } + int d = depth; + while(d--) + { + out << "[]"; + } + out << ';'; + out << nl << "for(int i" << iter << " = 0; i" << iter << " < len" << iter << "; i" << iter + << "++)"; + out << sb; + ostringstream o; + o << v << "[i" << iter << "]"; + if(isObject) + { + ostringstream patchParams; + out << nl << "final int fi" << iter << " = i" << iter << ";"; + patchParams << "value -> " << v << "[fi" << iter << "] = value, " << origContentS << ".class"; + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), false, iter, + customStream, StringList(), patchParams.str()); + } + else + { + writeMarshalUnmarshalCode(out, package, type, OptionalNone, false, 0, o.str(), false, iter, customStream); + } + out << eb; + iter++; + } + } + } +} + +bool +Slice::JavaGenerator::findMetaData(const string& prefix, const StringList& metaData, string& value) +{ + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) + { + if(q->find(prefix) == 0) + { + value = *q; + return true; + } + } + + return false; +} + +bool +Slice::JavaGenerator::getTypeMetaData(const StringList& metaData, string& instanceType, string& formalType) +{ + // + // Extract the instance type and an optional formal type. + // The correct syntax is "java:type:instance-type[:formal-type]". + // + static const string prefix = "java:type:"; + string directive; + if(findMetaData(prefix, metaData, directive)) + { + string::size_type pos = directive.find(':', prefix.size()); + if(pos != string::npos) + { + instanceType = directive.substr(prefix.size(), pos - prefix.size()); + formalType = directive.substr(pos + 1); + } + else + { + instanceType = directive.substr(prefix.size()); + formalType.clear(); + } + return true; + } + + return false; +} + +bool +Slice::JavaGenerator::hasTypeMetaData(const TypePtr& type, const StringList& localMetaData) +{ + ContainedPtr cont = ContainedPtr::dynamicCast(type); + if(cont) + { + static const string prefix = "java:type:"; + string directive; + + if(findMetaData(prefix, localMetaData, directive)) + { + return true; + } + + StringList metaData = cont->getMetaData(); + + if(findMetaData(prefix, metaData, directive)) + { + return true; + } + + if(findMetaData("java:protobuf:", metaData, directive) || + findMetaData("java:serializable:", metaData, directive)) + { + SequencePtr seq = SequencePtr::dynamicCast(cont); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && builtin->kind() == Builtin::KindByte) + { + return true; + } + } + } + + if(findMetaData("java:buffer", metaData, directive) || + findMetaData("java:buffer", localMetaData, directive)) + { + SequencePtr seq = SequencePtr::dynamicCast(cont); + if(seq) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin && + (builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + return true; + } + } + } + } + + return false; +} + +bool +Slice::JavaGenerator::getDictionaryTypes(const DictionaryPtr& dict, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType, + bool local) const +{ + // + // Get the types of the key and value. + // + string keyTypeStr = typeToObjectString(dict->keyType(), TypeModeIn, package, StringList(), true, local); + string valueTypeStr = typeToObjectString(dict->valueType(), TypeModeIn, package, StringList(), true, local); + + // + // Collect metadata for a custom type. + // + if(getTypeMetaData(metaData, instanceType, formalType) || + getTypeMetaData(dict->getMetaData(), instanceType, formalType)) + { + assert(!instanceType.empty()); + if(formalType.empty()) + { + formalType = "java.util.Map<" + keyTypeStr + ", " + valueTypeStr + ">"; + } + return true; + } + + // + // Return a default type for the platform. + // + instanceType = "java.util.HashMap<" + keyTypeStr + ", " + valueTypeStr + ">"; + formalType = "java.util.Map<" + keyTypeStr + ", " + valueTypeStr + ">"; + return false; +} + +bool +Slice::JavaGenerator::getSequenceTypes(const SequencePtr& seq, + const string& package, + const StringList& metaData, + string& instanceType, + string& formalType, + bool local) const +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type()); + if(builtin) + { + if(builtin->kind() == Builtin::KindByte) + { + string prefix = "java:serializable:"; + string meta; + if(seq->findMetaData(prefix, meta)) + { + instanceType = formalType = meta.substr(prefix.size()); + return true; + } + prefix = "java:protobuf:"; + if(seq->findMetaData(prefix, meta)) + { + instanceType = formalType = meta.substr(prefix.size()); + return true; + } + } + + if((builtin->kind() == Builtin::KindByte || builtin->kind() == Builtin::KindShort || + builtin->kind() == Builtin::KindInt || builtin->kind() == Builtin::KindLong || + builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble)) + { + string prefix = "java:buffer"; + string meta; + string ignore; + if(seq->findMetaData(prefix, meta) || findMetaData(prefix, metaData, ignore)) + { + instanceType = formalType = typeToBufferString(seq->type()); + return true; + } + } + } + + // + // Collect metadata for a custom type. + // + if(getTypeMetaData(metaData, instanceType, formalType) || + getTypeMetaData(seq->getMetaData(), instanceType, formalType)) + { + assert(!instanceType.empty()); + if(formalType.empty()) + { + formalType = "java.util.List<" + + typeToObjectString(seq->type(), TypeModeIn, package, StringList(), true, local) + ">"; + } + return true; + } + + // + // The default mapping is a native array. + // + instanceType = formalType = typeToString(seq->type(), TypeModeIn, package, metaData, true, false, local) + "[]"; + return false; +} + +JavaOutput* +Slice::JavaGenerator::createOutput() +{ + return new JavaOutput; +} + +void +Slice::JavaGenerator::validateMetaData(const UnitPtr& u) +{ + MetaDataVisitor visitor; + u->visit(&visitor, true); +} diff --git a/cpp/src/slice2php/Main.cpp b/cpp/src/slice2php/Main.cpp new file mode 100644 index 00000000000..09688ae0f3d --- /dev/null +++ b/cpp/src/slice2php/Main.cpp @@ -0,0 +1,1935 @@ +// ********************************************************************** +// +// 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 <IceUtil/CtrlCHandler.h> +#include <IceUtil/IceUtil.h> +#include <IceUtil/InputUtil.h> +#include <IceUtil/Options.h> +#include <IceUtil/OutputUtil.h> +#include <IceUtil/StringUtil.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/MutexPtrLock.h> +#include <IceUtil/ConsoleUtil.h> +#include <Slice/Checksum.h> +#include <Slice/Preprocessor.h> +#include <Slice/FileTracker.h> +#include <Slice/PHPUtil.h> +#include <Slice/Parser.h> +#include <Slice/Util.h> +#include <cstring> +#include <climits> + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +# include <direct.h> +#else +# include <unistd.h> +#endif + +using namespace std; +using namespace Slice; +using namespace Slice::PHP; +using namespace IceUtilInternal; + +namespace +{ + +// +// Get the fully-qualified name of the given definition. If a suffix is provided, +// it is prepended to the definition's unqualified name. If the nameSuffix +// is provided, it is appended to the container's name. +// +string +getAbsolute(const ContainedPtr& cont, bool ns, const string& pfx = std::string(), const string& suffix = std::string()) +{ + return scopedToName(cont->scope() + pfx + cont->name() + suffix, ns); +} + +} + +// +// CodeVisitor generates the PHP mapping for a translation unit. +// +class CodeVisitor : public ParserVisitor +{ +public: + + CodeVisitor(IceUtilInternal::Output&, bool); + + virtual void visitClassDecl(const ClassDeclPtr&); + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual bool visitExceptionStart(const ExceptionPtr&); + virtual bool visitStructStart(const StructPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + virtual void visitEnum(const EnumPtr&); + virtual void visitConst(const ConstPtr&); + +private: + + void startNamespace(const ContainedPtr&); + void endNamespace(); + + // + // Return the PHP name for the given Slice type. When using namespaces, + // this name is a relative (unqualified) name, otherwise this name is the + // flattened absolute name. + // + string getName(const ContainedPtr&, const string& = string()); + + // + // Return the PHP variable for the given object's type. + // + string getTypeVar(const ContainedPtr&, const string& = string()); + + // + // Emit the array for a Slice type. + // + void writeType(const TypePtr&); + + // + // Write a default value for a given type. + // + void writeDefaultValue(const DataMemberPtr&); + + struct MemberInfo + { + string fixedName; + bool inherited; + DataMemberPtr dataMember; + }; + typedef list<MemberInfo> MemberInfoList; + + // + // Write a member assignment statement for a constructor. + // + void writeAssign(const MemberInfo&); + + // + // Write constant value. + // + void writeConstantValue(const TypePtr&, const SyntaxTreeBasePtr&, const string&); + + // + // Write constructor parameters with default values. + // + void writeConstructorParams(const MemberInfoList&); + + // + // Convert an operation mode into a string. + // + string getOperationMode(Slice::Operation::Mode, bool); + + void collectClassMembers(const ClassDefPtr&, MemberInfoList&, bool); + void collectExceptionMembers(const ExceptionPtr&, MemberInfoList&, bool); + + Output& _out; + bool _ns; // Using namespaces? + list<string> _moduleStack; // TODO: Necessary? + set<string> _classHistory; // TODO: Necessary? +}; + +// +// CodeVisitor implementation. +// +CodeVisitor::CodeVisitor(Output& out, bool ns) : + _out(out), + _ns(ns) +{ +} + +void +CodeVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + // + // Handle forward declarations. + // + string scoped = p->scoped(); + if(_classHistory.count(scoped) == 0) + { + startNamespace(p); + + string type = getTypeVar(p); + _out << sp << nl << "global " << type << ';'; + + bool isInterface = p->isInterface(); + if(!p->isLocal() && (isInterface || p->definition()->allOperations().size() > 0)) + { + _out << nl << "global " << type << "Prx;"; + } + _out << nl << "if(!isset(" << type << "))"; + _out << sb; + _out << nl << type << " = IcePHP_declareClass('" << scoped << "');"; + if(!p->isLocal() && (isInterface || p->definition()->allOperations().size() > 0)) + { + _out << nl << type << "Prx = IcePHP_declareProxy('" << scoped << "');"; + } + _out << eb; + + endNamespace(); + + _classHistory.insert(scoped); // Avoid redundant declarations. + } +} + +bool +CodeVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return false; + } + + string scoped = p->scoped(); + string name = getName(p); + string type = getTypeVar(p); + string abs = getAbsolute(p, _ns); + string prxName = getName(p, "Prx"); + string prxType = getTypeVar(p, "Prx"); + string prxAbs = getAbsolute(p, _ns, "", "Prx"); + ClassList bases = p->bases(); + ClassDefPtr base; + OperationList ops = p->operations(); + DataMemberList members = p->dataMembers(); + bool isInterface = p->isInterface(); + bool isAbstract = isInterface || p->allOperations().size() > 0; // Don't use isAbstract() - see bug 3739 + + startNamespace(p); + + _out << sp << nl << "global " << type << ';'; + if(!p->isLocal() && isAbstract) + { + _out << nl << "global " << prxType << ';'; + } + + // + // Define the class. + // + if(isInterface) + { + if(p->isLocal()) + { + _out << nl << "interface " << name; + if(bases.empty()) + { + if(!p->isLocal()) + { + _out << " extends " << scopedToName("::Ice::Object", _ns); + } + } + else + { + _out << " extends "; + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + if(q != bases.begin()) + { + _out << ", "; + } + _out << getAbsolute(*q, _ns); + } + } + _out << sb; + for(OperationList::iterator oli = ops.begin(); oli != ops.end(); ++oli) + { + _out << nl << "public function " << fixIdent((*oli)->name()) << '('; + ParamDeclList params = (*oli)->parameters(); + for(ParamDeclList::iterator q = params.begin(); q != params.end(); ++q) + { + if(q != params.begin()) + { + _out << ", "; + } + _out << '$' << fixIdent((*q)->name()); + } + _out << ");"; + } + + _out << eb; + } + } + else + { + _out << nl; + _out << "class " << name; + if(!bases.empty() && !bases.front()->isInterface()) + { + base = bases.front(); + bases.pop_front(); + } + if(base) + { + _out << " extends " << getAbsolute(base, _ns); + } + else + { + if(!p->isLocal()) + { + _out << " extends " << scopedToName("::Ice::Value", _ns); + } + } + + // + // Value objects don't implement any interfaces. + // + if(p->isLocal() && !bases.empty()) + { + _out << " implements "; + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + if(q != bases.begin()) + { + _out << ", "; + } + _out << getAbsolute(*q, _ns); + } + } + + _out << sb; + + // + // __construct + // + _out << nl << "public function __construct("; + MemberInfoList allMembers; + collectClassMembers(p, allMembers, false); + writeConstructorParams(allMembers); + _out << ")"; + _out << sb; + if(base) + { + _out << nl << "parent::__construct("; + int count = 0; + for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q) + { + if(q->inherited) + { + if(count) + { + _out << ", "; + } + _out << '$' << q->fixedName; + ++count; + } + } + _out << ");"; + } + { + for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q) + { + if(!q->inherited) + { + writeAssign(*q); + } + } + } + _out << eb; + + if(!p->isLocal()) + { + // + // ice_ice + // + _out << sp << nl << "public function ice_id()"; + _out << sb; + _out << nl << "return '" << scoped << "';"; + _out << eb; + + // + // ice_staticId + // + _out << sp << nl << "public static function ice_staticId()"; + _out << sb; + _out << nl << "return '" << scoped << "';"; + _out << eb; + } + + // + // __toString + // + _out << sp << nl << "public function __toString()"; + _out << sb; + _out << nl << "global " << type << ';'; + _out << nl << "return IcePHP_stringify($this, " << type << ");"; + _out << eb; + + if(!members.empty()) + { + _out << sp; + bool isProtected = p->hasMetaData("protected"); + for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + { + _out << nl; + if(isProtected || (*q)->hasMetaData("protected")) + { + _out << "protected "; + } + else + { + _out << "public "; + } + _out << "$" << fixIdent((*q)->name()) << ";"; + } + } + + _out << eb; // End of class. + } + + // + // Define the proxy class. + // + if(!p->isLocal() && isAbstract) + { + _out << sp << nl << "class " << prxName << "Helper"; + _out << sb; + + _out << sp << nl << "public static function checkedCast($proxy, $facetOrContext=null, $context=null)"; + _out << sb; + _out << nl << "return $proxy->ice_checkedCast('" << scoped << "', $facetOrContext, $context);"; + _out << eb; + + _out << sp << nl << "public static function uncheckedCast($proxy, $facet=null)"; + _out << sb; + _out << nl << "return $proxy->ice_uncheckedCast('" << scoped << "', $facet);"; + _out << eb; + + _out << sp << nl << "public static function ice_staticId()"; + _out << sb; + _out << nl << "return '" << scoped << "';"; + _out << eb; + + _out << eb; + } + + if(_classHistory.count(scoped) == 0 && p->canBeCyclic()) + { + // + // Emit a forward declaration for the class in case a data member refers to this type. + // + _out << sp << nl << type << " = IcePHP_declareClass('" << scoped << "');"; + if(!p->isLocal() && isAbstract) + { + _out << nl << prxType << " = IcePHP_declareProxy('" << scoped << "');"; + } + } + + // + // Emit the type information. + // + const bool preserved = p->hasMetaData("preserve-slice") || p->inheritsMetaData("preserve-slice"); + _out << sp << nl << type << " = IcePHP_defineClass('" << scoped << "', '" << escapeName(abs) << "', " + << p->compactId() << ", " << (preserved ? "true" : "false") << ", " + << (isInterface ? "true" : "false") << ", "; + if(!base || (isInterface && !p->isLocal())) + { + _out << "$Ice__t_Value"; + } + else + { + _out << getTypeVar(base); + } + _out << ", "; + // + // Members + // + // Data members are represented as an array: + // + // ('MemberName', MemberType, Optional, Tag) + // + // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type. + // + if(!members.empty()) + { + _out << "array("; + for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + { + if(q != members.begin()) + { + _out << ','; + } + _out.inc(); + _out << nl << "array('" << fixIdent((*q)->name()) << "', "; + writeType((*q)->type()); + _out << ", " << ((*q)->optional() ? "true" : "false") << ", " + << ((*q)->optional() ? (*q)->tag() : 0) << ')'; + _out.dec(); + } + _out << ')'; + } + else + { + _out << "null"; + } + _out << ");"; + + if(!p->isLocal() && isAbstract) + { + _out << sp << nl << prxType << " = IcePHP_defineProxy('" << scoped << "', "; + if(!base || base->allOperations().empty()) + { + _out << "$Ice__t_ObjectPrx"; + } + else + { + _out << getTypeVar(base, "Prx"); + } + _out << ", "; + // + // Interfaces + // + if(!bases.empty()) + { + _out << "array("; + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + if(q != bases.begin()) + { + _out << ", "; + } + _out << getTypeVar(*q, "Prx"); + } + _out << ')'; + } + else + { + _out << "null"; + } + _out << ");"; + + // + // Define each operation. The arguments to IcePHP_defineOperation are: + // + // $ClassType, 'opName', Mode, SendMode, FormatType, (InParams), (OutParams), ReturnParam, (Exceptions) + // + // where InParams and OutParams are arrays of type descriptions, and Exceptions + // is an array of exception type ids. + // + if(!ops.empty()) + { + _out << sp; + for(OperationList::iterator oli = ops.begin(); oli != ops.end(); ++oli) + { + ParamDeclList params = (*oli)->parameters(); + ParamDeclList::iterator t; + int count; + + _out << nl << "IcePHP_defineOperation(" << prxType << ", '" << (*oli)->name() << "', " + << getOperationMode((*oli)->mode(), _ns) << ", " << getOperationMode((*oli)->sendMode(), _ns) + << ", " << static_cast<int>((*oli)->format()) << ", "; + for(t = params.begin(), count = 0; t != params.end(); ++t) + { + if(!(*t)->isOutParam()) + { + if(count == 0) + { + _out << "array("; + } + else if(count > 0) + { + _out << ", "; + } + _out << "array("; + writeType((*t)->type()); + if((*t)->optional()) + { + _out << ", " << (*t)->tag(); + } + _out << ')'; + ++count; + } + } + if(count > 0) + { + _out << ')'; + } + else + { + _out << "null"; + } + _out << ", "; + for(t = params.begin(), count = 0; t != params.end(); ++t) + { + if((*t)->isOutParam()) + { + if(count == 0) + { + _out << "array("; + } + else if(count > 0) + { + _out << ", "; + } + _out << "array("; + writeType((*t)->type()); + if((*t)->optional()) + { + _out << ", " << (*t)->tag(); + } + _out << ')'; + ++count; + } + } + if(count > 0) + { + _out << ')'; + } + else + { + _out << "null"; + } + _out << ", "; + TypePtr returnType = (*oli)->returnType(); + if(returnType) + { + // + // The return type has the same format as an in/out parameter: + // + // Type, Optional?, OptionalTag + // + _out << "array("; + writeType(returnType); + if((*oli)->returnIsOptional()) + { + _out << ", " << (*oli)->returnTag(); + } + _out << ')'; + } + else + { + _out << "null"; + } + _out << ", "; + ExceptionList exceptions = (*oli)->throws(); + if(!exceptions.empty()) + { + _out << "array("; + for(ExceptionList::iterator u = exceptions.begin(); u != exceptions.end(); ++u) + { + if(u != exceptions.begin()) + { + _out << ", "; + } + _out << getTypeVar(*u); + } + _out << ')'; + } + else + { + _out << "null"; + } + _out << ");"; + } + } + } + + endNamespace(); + + if(_classHistory.count(scoped) == 0) + { + _classHistory.insert(scoped); // Avoid redundant declarations. + } + + return false; +} + +bool +CodeVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return false; + } + + string scoped = p->scoped(); + string name = getName(p); + string type = getTypeVar(p); + string abs = getAbsolute(p, _ns); + + startNamespace(p); + + _out << sp << nl << "global " << type << ';'; + _out << nl << "class " << name << " extends "; + ExceptionPtr base = p->base(); + string baseName; + if(base) + { + baseName = getAbsolute(base, _ns); + _out << baseName; + } + else if(p->isLocal()) + { + _out << scopedToName("::Ice::LocalException", _ns); + } + else + { + _out << scopedToName("::Ice::UserException", _ns); + } + _out << sb; + + DataMemberList members = p->dataMembers(); + + // + // __construct + // + _out << nl << "public function __construct("; + MemberInfoList allMembers; + collectExceptionMembers(p, allMembers, false); + writeConstructorParams(allMembers); + _out << ")"; + _out << sb; + if(base) + { + _out << nl << "parent::__construct("; + int count = 0; + for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q) + { + if(q->inherited) + { + if(count) + { + _out << ", "; + } + _out << '$' << q->fixedName; + ++count; + } + } + _out << ");"; + } + for(MemberInfoList::iterator q = allMembers.begin(); q != allMembers.end(); ++q) + { + if(!q->inherited) + { + writeAssign(*q); + } + } + _out << eb; + + // + // ice_id + // + _out << sp << nl << "public function ice_id()"; + _out << sb; + _out << nl << "return '" << scoped << "';"; + _out << eb; + + // + // __toString + // + _out << sp << nl << "public function __toString()"; + _out << sb; + _out << nl << "global " << type << ';'; + _out << nl << "return IcePHP_stringifyException($this, " << type << ");"; + _out << eb; + + if(!members.empty()) + { + _out << sp; + for(DataMemberList::iterator dmli = members.begin(); dmli != members.end(); ++dmli) + { + _out << nl << "public $" << fixIdent((*dmli)->name()) << ";"; + } + } + + _out << eb; + + // + // Emit the type information. + // + const bool preserved = p->hasMetaData("preserve-slice") || p->inheritsMetaData("preserve-slice"); + _out << sp << nl << type << " = IcePHP_defineException('" << scoped << "', '" << escapeName(abs) << "', " + << (preserved ? "true" : "false") << ", "; + if(!base) + { + _out << "null"; + } + else + { + _out << getTypeVar(base); + } + _out << ", "; + // + // Data members are represented as an array: + // + // ('MemberName', MemberType, Optional, Tag) + // + // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type. + // + if(!members.empty()) + { + _out << "array("; + for(DataMemberList::iterator dmli = members.begin(); dmli != members.end(); ++dmli) + { + if(dmli != members.begin()) + { + _out << ','; + } + _out.inc(); + _out << nl << "array('" << fixIdent((*dmli)->name()) << "', "; + writeType((*dmli)->type()); + _out << ", " << ((*dmli)->optional() ? "true" : "false") << ", " + << ((*dmli)->optional() ? (*dmli)->tag() : 0) << ')'; + _out.dec(); + } + _out << ')'; + } + else + { + _out << "null"; + } + _out << ");"; + + endNamespace(); + + return false; +} + +bool +CodeVisitor::visitStructStart(const StructPtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return false; + } + + string scoped = p->scoped(); + string name = getName(p); + string type = getTypeVar(p); + string abs = getAbsolute(p, _ns); + MemberInfoList memberList; + + { + DataMemberList members = p->dataMembers(); + for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + { + memberList.push_back(MemberInfo()); + memberList.back().fixedName = fixIdent((*q)->name()); + memberList.back().inherited = false; + memberList.back().dataMember = *q; + } + } + + startNamespace(p); + + _out << sp << nl << "global " << type << ';'; + + _out << nl << "class " << name; + _out << sb; + _out << nl << "public function __construct("; + writeConstructorParams(memberList); + _out << ")"; + _out << sb; + for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r) + { + writeAssign(*r); + } + _out << eb; + + // + // __toString + // + _out << sp << nl << "public function __toString()"; + _out << sb; + _out << nl << "global " << type << ';'; + _out << nl << "return IcePHP_stringify($this, " << type << ");"; + _out << eb; + + if(!memberList.empty()) + { + _out << sp; + for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r) + { + _out << nl << "public $" << r->fixedName << ';'; + } + } + + _out << eb; + + // + // Emit the type information. + // + _out << sp << nl << type << " = IcePHP_defineStruct('" << scoped << "', '" << escapeName(abs) << "', array("; + // + // Data members are represented as an array: + // + // ('MemberName', MemberType) + // + // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type. + // + for(MemberInfoList::iterator r = memberList.begin(); r != memberList.end(); ++r) + { + if(r != memberList.begin()) + { + _out << ", "; + } + _out.inc(); + _out << nl << "array('" << r->fixedName << "', "; + writeType(r->dataMember->type()); + _out << ')'; + _out.dec(); + } + _out << "));"; + endNamespace(); + + return false; +} + +void +CodeVisitor::visitSequence(const SequencePtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return; + } + + string type = getTypeVar(p); + TypePtr content = p->type(); + + startNamespace(p); + + // + // Emit the type information. + // + string scoped = p->scoped(); + _out << sp << nl << "global " << type << ';'; + _out << sp << nl << "if(!isset(" << type << "))"; + _out << sb; + _out << nl << type << " = IcePHP_defineSequence('" << scoped << "', "; + writeType(content); + _out << ");"; + _out << eb; + + endNamespace(); +} + +void +CodeVisitor::visitDictionary(const DictionaryPtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return; + } + + TypePtr keyType = p->keyType(); + BuiltinPtr b = BuiltinPtr::dynamicCast(keyType); + + const UnitPtr unit = p->unit(); + const DefinitionContextPtr dc = unit->findDefinitionContext(p->file()); + assert(dc); + if(b) + { + switch(b->kind()) + { + case Slice::Builtin::KindBool: + case Slice::Builtin::KindByte: + case Slice::Builtin::KindShort: + case Slice::Builtin::KindInt: + case Slice::Builtin::KindLong: + case Slice::Builtin::KindString: + // + // These types are acceptable as dictionary keys. + // + break; + + case Slice::Builtin::KindFloat: + case Slice::Builtin::KindDouble: + { + dc->warning(InvalidMetaData, p->file(), p->line(), "dictionary key type not supported in PHP"); + break; + } + + case Slice::Builtin::KindObject: + case Slice::Builtin::KindObjectProxy: + case Slice::Builtin::KindLocalObject: + case Slice::Builtin::KindValue: + assert(false); + } + } + else if(!EnumPtr::dynamicCast(keyType)) + { + dc->warning(InvalidMetaData, p->file(), p->line(), "dictionary key type not supported in PHP"); + } + + string type = getTypeVar(p); + + startNamespace(p); + + // + // Emit the type information. + // + string scoped = p->scoped(); + _out << sp << nl << "global " << type << ';'; + _out << sp << nl << "if(!isset(" << type << "))"; + _out << sb; + _out << nl << type << " = IcePHP_defineDictionary('" << scoped << "', "; + writeType(p->keyType()); + _out << ", "; + writeType(p->valueType()); + _out << ");"; + _out << eb; + + endNamespace(); +} + +void +CodeVisitor::visitEnum(const EnumPtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return; + } + + string scoped = p->scoped(); + string name = getName(p); + string type = getTypeVar(p); + string abs = getAbsolute(p, _ns); + EnumeratorList enums = p->enumerators(); + + startNamespace(p); + + _out << sp << nl << "global " << type << ';'; + _out << nl << "class " << name; + _out << sb; + + { + long i = 0; + for(EnumeratorList::iterator q = enums.begin(); q != enums.end(); ++q, ++i) + { + _out << nl << "const " << fixIdent((*q)->name()) << " = " << (*q)->value() << ';'; + } + } + + _out << eb; + + // + // Emit the type information. + // + _out << sp << nl << type << " = IcePHP_defineEnum('" << scoped << "', array("; + for(EnumeratorList::iterator q = enums.begin(); q != enums.end(); ++q) + { + if(q != enums.begin()) + { + _out << ", "; + } + _out << "'" << (*q)->name() << "', " << (*q)->value(); + } + _out << "));"; + + endNamespace(); +} + +void +CodeVisitor::visitConst(const ConstPtr& p) +{ + // + // Do not generate any code for php:internal types, those are provided by + // IcePHP C++ extension. + // + StringList metadata = p->getMetaData(); + if(find(metadata.begin(), metadata.end(), "php:internal") != metadata.end()) + { + return; + } + + string name = getName(p); + string type = getTypeVar(p); + string abs = getAbsolute(p, _ns); + + startNamespace(p); + + _out << sp << nl << "if(!defined('" << escapeName(abs) << "'))"; + _out << sb; + if(_ns) + { + _out << sp << nl << "define(__NAMESPACE__ . '\\\\" << name << "', "; + } + else + { + _out << sp << nl << "define('" << name << "', "; + } + + writeConstantValue(p->type(), p->valueType(), p->value()); + + _out << ");"; + _out << eb; + + endNamespace(); +} + +void +CodeVisitor::startNamespace(const ContainedPtr& cont) +{ + if(_ns) + { + string scope = cont->scope(); + scope = scope.substr(2); // Removing leading '::' + scope = scope.substr(0, scope.length() - 2); // Removing trailing '::' + _out << sp << nl << "namespace " << scopedToName(scope, true); + _out << sb; + } +} + +void +CodeVisitor::endNamespace() +{ + if(_ns) + { + _out << eb; + } +} + +string +CodeVisitor::getTypeVar(const ContainedPtr& p, const string& suffix) +{ + return "$" + getAbsolute(p, false, "_t_", suffix); +} + +string +CodeVisitor::getName(const ContainedPtr& p, const string& suffix) +{ + if(_ns) + { + return fixIdent(p->name() + suffix); + } + else + { + return getAbsolute(p, false, "", suffix); + } +} + +void +CodeVisitor::writeType(const TypePtr& p) +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + _out << "$IcePHP__t_bool"; + break; + } + case Builtin::KindByte: + { + _out << "$IcePHP__t_byte"; + break; + } + case Builtin::KindShort: + { + _out << "$IcePHP__t_short"; + break; + } + case Builtin::KindInt: + { + _out << "$IcePHP__t_int"; + break; + } + case Builtin::KindLong: + { + _out << "$IcePHP__t_long"; + break; + } + case Builtin::KindFloat: + { + _out << "$IcePHP__t_float"; + break; + } + case Builtin::KindDouble: + { + _out << "$IcePHP__t_double"; + break; + } + case Builtin::KindString: + { + _out << "$IcePHP__t_string"; + break; + } + case Builtin::KindObject: + case Builtin::KindValue: + { + _out << "$Ice__t_Value"; + break; + } + case Builtin::KindObjectProxy: + { + _out << "$Ice__t_ObjectPrx"; + break; + } + case Builtin::KindLocalObject: + { + _out << "$Ice__t_LocalObject"; + break; + } + } + return; + } + + ProxyPtr prx = ProxyPtr::dynamicCast(p); + if(prx) + { + ClassDefPtr def = prx->_class()->definition(); + if(def->isInterface() || def->allOperations().size() > 0) + { + _out << getTypeVar(prx->_class(), "Prx"); + } + else + { + _out << "$Ice__t_ObjectPrx"; + } + return; + } + + ContainedPtr cont = ContainedPtr::dynamicCast(p); + assert(cont); + _out << getTypeVar(cont); +} + +void +CodeVisitor::writeDefaultValue(const DataMemberPtr& m) +{ + TypePtr p = m->type(); + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + _out << "false"; + break; + } + case Builtin::KindByte: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + { + _out << "0"; + break; + } + case Builtin::KindFloat: + case Builtin::KindDouble: + { + _out << "0.0"; + break; + } + case Builtin::KindString: + { + _out << "''"; + break; + } + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + case Builtin::KindValue: + { + _out << "null"; + break; + } + } + return; + } + + EnumPtr en = EnumPtr::dynamicCast(p); + if(en) + { + EnumeratorList enums = en->enumerators(); + _out << getAbsolute(en, _ns) << "::" << fixIdent(enums.front()->name()); + return; + } + + // + // PHP does not allow the following construct: + // + // function foo($theStruct=new MyStructType) + // + // Instead we use null as the default value and allocate an instance in + // the constructor. + // + if(StructPtr::dynamicCast(p)) + { + _out << "null"; + return; + } + + _out << "null"; +} + +void +CodeVisitor::writeAssign(const MemberInfo& info) +{ + StructPtr st = StructPtr::dynamicCast(info.dataMember->type()); + if(st) + { + _out << nl << "$this->" << info.fixedName << " = is_null($" << info.fixedName << ") ? new " + << getAbsolute(st, _ns) << " : $" << info.fixedName << ';'; + } + else + { + _out << nl << "$this->" << info.fixedName << " = $" << info.fixedName << ';'; + } +} + +void +CodeVisitor::writeConstantValue(const TypePtr& type, const SyntaxTreeBasePtr& valueType, const string& value) +{ + ConstPtr constant = ConstPtr::dynamicCast(valueType); + if(constant) + { + _out << getAbsolute(constant, _ns); + } + else + { + Slice::BuiltinPtr b = Slice::BuiltinPtr::dynamicCast(type); + Slice::EnumPtr en = Slice::EnumPtr::dynamicCast(type); + if(b) + { + switch(b->kind()) + { + case Slice::Builtin::KindBool: + case Slice::Builtin::KindByte: + case Slice::Builtin::KindShort: + case Slice::Builtin::KindInt: + case Slice::Builtin::KindFloat: + case Slice::Builtin::KindDouble: + { + _out << value; + break; + } + case Slice::Builtin::KindLong: + { + IceUtil::Int64 l; + IceUtilInternal::stringToInt64(value, l); + // + // The platform's 'long' type may not be 64 bits, so we store 64-bit + // values as a string. + // + if(sizeof(IceUtil::Int64) > sizeof(long) && (l < LONG_MIN || l > LONG_MAX)) + { + _out << "'" << value << "'"; + } + else + { + _out << value; + } + break; + } + case Slice::Builtin::KindString: + { + // PHP 7.x also supports an EC6UCN-like notation, see: + // https://wiki.php.net/rfc/unicode_escape + // + _out << "\"" << toStringLiteral(value, "\f\n\r\t\v\x1b", "$", Octal, 0) << "\""; + break; + } + case Slice::Builtin::KindObject: + case Slice::Builtin::KindObjectProxy: + case Slice::Builtin::KindLocalObject: + case Slice::Builtin::KindValue: + assert(false); + } + } + else if(en) + { + EnumeratorPtr lte = EnumeratorPtr::dynamicCast(valueType); + assert(lte); + _out << getAbsolute(en, _ns) << "::" << fixIdent(lte->name()); + } + else + { + assert(false); // Unknown const type. + } + } +} + +void +CodeVisitor::writeConstructorParams(const MemberInfoList& members) +{ + for(MemberInfoList::const_iterator p = members.begin(); p != members.end(); ++p) + { + if(p != members.begin()) + { + _out << ", "; + } + _out << '$' << p->fixedName << "="; + + const DataMemberPtr member = p->dataMember; + if(member->defaultValueType()) + { + writeConstantValue(member->type(), member->defaultValueType(), member->defaultValue()); + } + else if(member->optional()) + { + _out << "Ice_Unset"; + } + else + { + writeDefaultValue(member); + } + } +} + +string +CodeVisitor::getOperationMode(Slice::Operation::Mode mode, bool /*ns*/) +{ + ostringstream ostr; + ostr << static_cast<int>(mode); + return ostr.str(); +} + +void +CodeVisitor::collectClassMembers(const ClassDefPtr& p, MemberInfoList& allMembers, bool inherited) +{ + ClassList bases = p->bases(); + if(!bases.empty() && !bases.front()->isInterface()) + { + collectClassMembers(bases.front(), allMembers, true); + } + + DataMemberList members = p->dataMembers(); + + for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + { + MemberInfo m; + m.fixedName = fixIdent((*q)->name()); + m.inherited = inherited; + m.dataMember = *q; + allMembers.push_back(m); + } +} + +void +CodeVisitor::collectExceptionMembers(const ExceptionPtr& p, MemberInfoList& allMembers, bool inherited) +{ + ExceptionPtr base = p->base(); + if(base) + { + collectExceptionMembers(base, allMembers, true); + } + + DataMemberList members = p->dataMembers(); + + for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) + { + MemberInfo m; + m.fixedName = fixIdent((*q)->name()); + m.inherited = inherited; + m.dataMember = *q; + allMembers.push_back(m); + } +} + +static void +generate(const UnitPtr& un, bool all, bool checksum, bool ns, const vector<string>& includePaths, Output& out) +{ + if(!all) + { + vector<string> paths = includePaths; + for(vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) + { + *p = fullPath(*p); + } + + StringList includes = un->includeFiles(); + if(!includes.empty()) + { + if(ns) + { + out << sp; + out << nl << "namespace"; + out << sb; + } + for(StringList::const_iterator q = includes.begin(); q != includes.end(); ++q) + { + string file = changeInclude(*q, paths); + out << nl << "require_once '" << file << ".php';"; + } + if(ns) + { + out << eb; + } + } + } + + CodeVisitor codeVisitor(out, ns); + un->visit(&codeVisitor, false); + + if(checksum) + { + ChecksumMap checksums = createChecksums(un); + if(!checksums.empty()) + { + out << sp; + if(ns) + { + out << "namespace"; // Global namespace. + out << sb; + } + for(ChecksumMap::const_iterator p = checksums.begin(); p != checksums.end(); ++p) + { + out << nl << "$Ice_sliceChecksums[\"" << p->first << "\"] = \""; + ostringstream str; + str.flags(ios_base::hex); + str.fill('0'); + for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q) + { + str << static_cast<int>(*q); + } + out << str.str() << "\";"; + } + if(ns) + { + out << eb; + } + } + } + + out << nl; // Trailing newline. +} + +static void +printHeader(IceUtilInternal::Output& out) +{ + static const char* header = + "// **********************************************************************\n" + "//\n" + "// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.\n" + "//\n" + "// This copy of Ice is licensed to you under the terms described in the\n" + "// ICE_LICENSE file included in this distribution.\n" + "//\n" + "// **********************************************************************\n" + ; + + out << header; + out << "//\n"; + out << "// Ice version " << ICE_STRING_VERSION << "\n"; + out << "//\n"; +} + +namespace +{ + +IceUtil::Mutex* globalMutex = 0; +bool interrupted = false; + +class Init +{ +public: + + Init() + { + globalMutex = new IceUtil::Mutex; + } + + ~Init() + { + delete globalMutex; + globalMutex = 0; + } +}; + +Init init; + +} + +static void +interruptedCallback(int /*signal*/) +{ + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); + + interrupted = true; +} + +static void +usage(const string& n) +{ + consoleErr << "Usage: " << n << " [options] slice-files...\n"; + consoleErr << + "Options:\n" + "-h, --help Show this message.\n" + "-v, --version Display the Ice version.\n" + "--validate Validate command line options.\n" + "-DNAME Define NAME as 1.\n" + "-DNAME=DEF Define NAME as DEF.\n" + "-UNAME Remove any definition for NAME.\n" + "-IDIR Put DIR in the include file search path.\n" + "-E Print preprocessor output on stdout.\n" + "--output-dir DIR Create files in the directory DIR.\n" + "--depend Generate Makefile dependencies.\n" + "--depend-xml Generate dependencies in XML format.\n" + "--depend-file FILE Write dependencies to FILE instead of standard output.\n" + "-d, --debug Print debug messages.\n" + "--all Generate code for Slice definitions in included files.\n" + "--checksum Generate checksums for Slice definitions.\n" + "--no-namespace Do not use PHP namespaces (deprecated).\n" + "--ice Allow reserved Ice prefix in Slice identifiers\n" + " deprecated: use instead [[\"ice-prefix\"]] metadata.\n" + "--underscore Allow underscores in Slice identifiers\n" + " deprecated: use instead [[\"underscore\"]] metadata.\n" + ; +} + +int +compile(const vector<string>& argv) +{ + IceUtilInternal::Options opts; + opts.addOpt("h", "help"); + opts.addOpt("v", "version"); + opts.addOpt("", "validate"); + opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("E"); + opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "depend"); + opts.addOpt("", "depend-xml"); + opts.addOpt("", "depend-file", IceUtilInternal::Options::NeedArg, ""); + opts.addOpt("d", "debug"); + opts.addOpt("", "ice"); + opts.addOpt("", "underscore"); + opts.addOpt("", "all"); + opts.addOpt("", "checksum"); + opts.addOpt("n", "no-namespace"); + + bool validate = find(argv.begin(), argv.end(), "--validate") != argv.end(); + + vector<string> args; + try + { + args = opts.parse(argv); + } + catch(const IceUtilInternal::BadOptException& e) + { + consoleErr << argv[0] << ": error: " << e.reason << endl; + if(!validate) + { + usage(argv[0]); + } + return EXIT_FAILURE; + } + + if(opts.isSet("help")) + { + usage(argv[0]); + return EXIT_SUCCESS; + } + + if(opts.isSet("version")) + { + consoleErr << ICE_STRING_VERSION << endl; + return EXIT_SUCCESS; + } + + vector<string> cppArgs; + vector<string> optargs = opts.argVec("D"); + for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-D" + *i); + } + + optargs = opts.argVec("U"); + for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-U" + *i); + } + + vector<string> includePaths = opts.argVec("I"); + for(vector<string>::const_iterator i = includePaths.begin(); i != includePaths.end(); ++i) + { + cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i)); + } + + bool preprocess = opts.isSet("E"); + + string output = opts.optArg("output-dir"); + + bool depend = opts.isSet("depend"); + + bool dependxml = opts.isSet("depend-xml"); + + string dependFile = opts.optArg("depend-file"); + + bool debug = opts.isSet("debug"); + + bool ice = opts.isSet("ice"); + + bool underscore = opts.isSet("underscore"); + + bool all = opts.isSet("all"); + + bool checksum = opts.isSet("checksum"); + + bool ns = !opts.isSet("no-namespace"); + + if(args.empty()) + { + consoleErr << argv[0] << ": error: no input file" << endl; + if(!validate) + { + usage(argv[0]); + } + return EXIT_FAILURE; + } + + if(depend && dependxml) + { + consoleErr << argv[0] << ": error: cannot specify both --depend and --depend-xml" << endl; + if(!validate) + { + usage(argv[0]); + } + return EXIT_FAILURE; + } + + if(validate) + { + return EXIT_SUCCESS; + } + + int status = EXIT_SUCCESS; + + IceUtil::CtrlCHandler ctrlCHandler; + ctrlCHandler.setCallback(interruptedCallback); + + ostringstream os; + if(dependxml) + { + os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dependencies>" << endl; + } + + for(vector<string>::const_iterator i = args.begin(); i != args.end(); ++i) + { + // + // Ignore duplicates. + // + vector<string>::iterator p = find(args.begin(), args.end(), *i); + if(p != i) + { + continue; + } + + if(depend || dependxml) + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); + FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2PHP__"); + + if(cppHandle == 0) + { + return EXIT_FAILURE; + } + + UnitPtr u = Unit::createUnit(false, false, ice, underscore); + int parseStatus = u->parse(*i, cppHandle, debug); + u->destroy(); + + if(parseStatus == EXIT_FAILURE) + { + return EXIT_FAILURE; + } + + if(!icecpp->printMakefileDependencies(os, depend ? Preprocessor::PHP : Preprocessor::SliceXML, + includePaths, "-D__SLICE2PHP__")) + { + return EXIT_FAILURE; + } + + if(!icecpp->close()) + { + return EXIT_FAILURE; + } + } + else + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); + FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2PHP__"); + + if(cppHandle == 0) + { + return EXIT_FAILURE; + } + + if(preprocess) + { + char buf[4096]; + while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != ICE_NULLPTR) + { + if(fputs(buf, stdout) == EOF) + { + return EXIT_FAILURE; + } + } + if(!icecpp->close()) + { + return EXIT_FAILURE; + } + } + else + { + UnitPtr u = Unit::createUnit(false, all, ice, underscore); + int parseStatus = u->parse(*i, cppHandle, debug); + + if(!icecpp->close()) + { + u->destroy(); + return EXIT_FAILURE; + } + + if(parseStatus == EXIT_FAILURE) + { + status = EXIT_FAILURE; + } + else + { + string base = icecpp->getBaseName(); + string::size_type pos = base.find_last_of("/\\"); + if(pos != string::npos) + { + base.erase(0, pos + 1); + } + + string file = base + ".php"; + if(!output.empty()) + { + file = output + '/' + file; + } + + try + { + IceUtilInternal::Output out; + out.open(file.c_str()); + if(!out) + { + ostringstream os; + os << "cannot open`" << file << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addFile(file); + + out << "<?php\n"; + printHeader(out); + printGeneratedHeader(out, base + ".ice"); + + // + // Generate the PHP mapping. + // + generate(u, all, checksum, ns, includePaths, out); + + out << "?>\n"; + out.close(); + } + catch(const Slice::FileException& ex) + { + // If a file could not be created, then cleanup any + // created files. + FileTracker::instance()->cleanup(); + u->destroy(); + consoleErr << argv[0] << ": error: " << ex.reason() << endl; + return EXIT_FAILURE; + } + catch(const string& err) + { + FileTracker::instance()->cleanup(); + consoleErr << argv[0] << ": error: " << err << endl; + status = EXIT_FAILURE; + } + } + + u->destroy(); + } + } + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); + + if(interrupted) + { + FileTracker::instance()->cleanup(); + return EXIT_FAILURE; + } + } + } + + if(dependxml) + { + os << "</dependencies>\n"; + } + + if(depend || dependxml) + { + writeDependencies(os.str(), dependFile); + } + + return status; +} + +#ifdef _WIN32 +int wmain(int argc, wchar_t* argv[]) +#else +int main(int argc, char* argv[]) +#endif +{ + vector<string> args = Slice::argvToArgs(argc, argv); + try + { + return compile(args); + } + catch(const std::exception& ex) + { + consoleErr << args[0] << ": error:" << ex.what() << endl; + return EXIT_FAILURE; + } + catch(const std::string& msg) + { + consoleErr << args[0] << ": error:" << msg << endl; + return EXIT_FAILURE; + } + catch(const char* msg) + { + consoleErr << args[0] << ": error:" << msg << endl; + return EXIT_FAILURE; + } + catch(...) + { + consoleErr << args[0] << ": error:" << "unknown exception" << endl; + return EXIT_FAILURE; + } +} diff --git a/cpp/src/slice2py/Slice2Py.rc b/cpp/src/slice2py/Slice2Py.rc new file mode 100644 index 00000000000..916b4be8d9f --- /dev/null +++ b/cpp/src/slice2py/Slice2Py.rc @@ -0,0 +1,33 @@ +#include<IceUtil/ResourceConfig.h> + +#define ICE_INTERNALNAME "slice2py\0" +#define ICE_ORIGINALFILENAME "slice2py.exe\0" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION ICE_VERSION +PRODUCTVERSION ICE_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +FILESUBTYPE VFT2_UNKNOWN +FILEFLAGS VER_DEBUG +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", ICE_COMPANY_NAME + VALUE "FileDescription", "Slice to Python Translator\0" + VALUE "FileVersion", ICE_STRING_VERSION + VALUE "InternalName", ICE_INTERNALNAME + VALUE "LegalCopyright", ICE_COPYRIGHT + VALUE "OriginalFilename", ICE_ORIGINALFILENAME + VALUE "ProductName", ICE_PRODUCT_NAME + VALUE "ProductVersion", ICE_STRING_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/cpp/test/Ice/acm/Client.cpp b/cpp/test/Ice/acm/Client.cpp new file mode 100644 index 00000000000..97e4b999c7a --- /dev/null +++ b/cpp/test/Ice/acm/Client.cpp @@ -0,0 +1,48 @@ +// ********************************************************************** +// +// 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 <Ice/Ice.h> +#include <TestCommon.h> +#include <Test.h> + +DEFINE_TEST("client") + +using namespace std; + +int +run(int, char**, const Ice::CommunicatorPtr& communicator) +{ + void allTests(const Ice::CommunicatorPtr&); + allTests(communicator); + return EXIT_SUCCESS; +} + +int +main(int argc, char* argv[]) +{ +#ifdef ICE_STATIC_LIBS + Ice::registerIceSSL(); +# if defined(__linux) + Ice::registerIceBT(); +# endif +#endif + + try + { + Ice::InitializationData initData = getTestInitData(argc, argv); + initData.properties->setProperty("Ice.Warn.Connections", "0"); + + Ice::CommunicatorHolder ich = Ice::initialize(argc, argv, initData); + return run(argc, argv, ich.communicator()); + } + catch(const Ice::Exception& ex) + { + cerr << ex << endl; + return EXIT_FAILURE; + } +} |