summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/src/IceGrid/Parser.cpp2964
-rw-r--r--cpp/src/IceStorm/Parser.cpp732
-rw-r--r--cpp/src/Slice/JavaUtil.cpp5045
-rw-r--r--cpp/src/slice2php/Main.cpp1935
-rw-r--r--cpp/src/slice2py/Slice2Py.rc33
-rw-r--r--cpp/test/Ice/acm/Client.cpp48
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;
+ }
+}