diff options
author | Joe George <joe@zeroc.com> | 2015-03-03 17:30:50 -0500 |
---|---|---|
committer | Joe George <joe@zeroc.com> | 2015-05-12 11:41:55 -0400 |
commit | d35bb9f5c19e34aee31f83d445695a8186ef675e (patch) | |
tree | d5324eaf44f5f9776495537c51653f50a66a7237 /cpp/src/IceGrid/DescriptorHelper.cpp | |
download | ice-d35bb9f5c19e34aee31f83d445695a8186ef675e.tar.bz2 ice-d35bb9f5c19e34aee31f83d445695a8186ef675e.tar.xz ice-d35bb9f5c19e34aee31f83d445695a8186ef675e.zip |
Ice 3.4.2 Source Distributionv3.4.2
Diffstat (limited to 'cpp/src/IceGrid/DescriptorHelper.cpp')
-rw-r--r-- | cpp/src/IceGrid/DescriptorHelper.cpp | 3198 |
1 files changed, 3198 insertions, 0 deletions
diff --git a/cpp/src/IceGrid/DescriptorHelper.cpp b/cpp/src/IceGrid/DescriptorHelper.cpp new file mode 100644 index 00000000000..9126c2fc7b4 --- /dev/null +++ b/cpp/src/IceGrid/DescriptorHelper.cpp @@ -0,0 +1,3198 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 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 <IceGrid/DescriptorHelper.h> +#include <IceGrid/Util.h> + +#include <iterator> + +using namespace std; +using namespace IceUtil; +using namespace IceUtilInternal; +using namespace IceGrid; + +namespace IceGrid +{ + +struct GetReplicaGroupId : unary_function<ReplicaGroupDescriptor&, const string&> +{ + const string& + operator()(const ReplicaGroupDescriptor& desc) + { + return desc.id; + } +}; + +struct TemplateDescriptorEqual : std::binary_function<TemplateDescriptor&, TemplateDescriptor&, bool> +{ + bool + operator()(const TemplateDescriptor& lhs, const TemplateDescriptor& rhs) + { + if(lhs.parameters != rhs.parameters) + { + return false; + } + + if(lhs.parameterDefaults != rhs.parameterDefaults) + { + return false; + } + + { + IceBoxDescriptorPtr slhs = IceBoxDescriptorPtr::dynamicCast(lhs.descriptor); + IceBoxDescriptorPtr srhs = IceBoxDescriptorPtr::dynamicCast(rhs.descriptor); + if(slhs && srhs) + { + return IceBoxHelper(slhs) == IceBoxHelper(srhs); + } + } + { + ServerDescriptorPtr slhs = ServerDescriptorPtr::dynamicCast(lhs.descriptor); + ServerDescriptorPtr srhs = ServerDescriptorPtr::dynamicCast(rhs.descriptor); + if(slhs && srhs) + { + return ServerHelper(slhs) == ServerHelper(srhs); + } + } + { + ServiceDescriptorPtr slhs = ServiceDescriptorPtr::dynamicCast(lhs.descriptor); + ServiceDescriptorPtr srhs = ServiceDescriptorPtr::dynamicCast(rhs.descriptor); + if(slhs && srhs) + { + return ServiceHelper(slhs) == ServiceHelper(srhs); + } + } + + return false; + } +}; + +struct ReplicaGroupEq : std::binary_function<ReplicaGroupDescriptor&, ReplicaGroupDescriptor&, bool> +{ + bool + operator()(const ReplicaGroupDescriptor& lhs, const ReplicaGroupDescriptor& rhs) + { + if(lhs.id != rhs.id) + { + return false; + } + if(set<ObjectDescriptor>(lhs.objects.begin(), lhs.objects.end()) != + set<ObjectDescriptor>(rhs.objects.begin(), rhs.objects.end())) + { + return false; + } + if(lhs.loadBalancing && rhs.loadBalancing) + { + if(lhs.loadBalancing->ice_id() != rhs.loadBalancing->ice_id()) + { + return false; + } + if(lhs.loadBalancing->nReplicas != rhs.loadBalancing->nReplicas) + { + return false; + } + AdaptiveLoadBalancingPolicyPtr alhs = AdaptiveLoadBalancingPolicyPtr::dynamicCast(lhs.loadBalancing); + AdaptiveLoadBalancingPolicyPtr arhs = AdaptiveLoadBalancingPolicyPtr::dynamicCast(rhs.loadBalancing); + if(alhs && arhs && alhs->loadSample != arhs->loadSample) + { + return false; + } + } + else if(lhs.loadBalancing || rhs.loadBalancing) + { + return false; + } + + return true; + } +}; + +template <typename GetKeyFunc, typename Seq> Seq +getSeqUpdatedElts(const Seq& lseq, const Seq& rseq, GetKeyFunc func) +{ +#if defined(_MSC_VER) && (_MSC_VER < 1300) + return getSeqUpdatedEltsWithEq(lseq, rseq, func, equal_to<Seq::value_type>()); +#else + return getSeqUpdatedEltsWithEq(lseq, rseq, func, equal_to<typename Seq::value_type>()); +#endif +} + +template <typename GetKeyFunc, typename EqFunc, typename Seq> Seq +#if defined(_MSC_VER) && (_MSC_VER < 1300) +getSeqUpdatedEltsWithEq(const Seq& lseq, const Seq& rseq, GetKeyFunc func, EqFunc eq) +#else +getSeqUpdatedEltsWithEq(const Seq& lseq, const Seq& rseq, GetKeyFunc func, EqFunc eq) +#endif +{ + Seq result; + for(typename Seq::const_iterator p = rseq.begin(); p != rseq.end(); ++p) + { + typename Seq::const_iterator q = lseq.begin(); + for(; q != lseq.end(); ++q) + { + if(func(*p) == func(*q)) + { + break; + } + } + if(q == lseq.end() || !eq(*p, *q)) + { + result.push_back(*p); + } + } + return result; +} + +template <typename GetKeyFunc, typename Seq> Ice::StringSeq +getSeqRemovedElts(const Seq& lseq, const Seq& rseq, GetKeyFunc func) +{ + Ice::StringSeq removed; + for(typename Seq::const_iterator p = lseq.begin(); p != lseq.end(); ++p) + { + typename Seq::const_iterator q; + for(q = rseq.begin(); q != rseq.end(); ++q) + { + if(func(*p) == func(*q)) + { + break; + } + } + if(q == rseq.end()) + { + removed.push_back(func(*p)); + } + } + return removed; +} + +template <typename GetKeyFunc, typename Seq> Seq +updateSeqElts(const Seq& seq, const Seq& update, const Ice::StringSeq& remove, GetKeyFunc func) +{ + Seq result = update; + set<string> removed(remove.begin(), remove.end()); + for(typename Seq::const_iterator p = seq.begin(); p != seq.end(); ++p) + { + if(removed.find(func(*p)) == removed.end()) + { + typename Seq::const_iterator q = update.begin(); + for(; q != update.end(); ++q) + { + if(func(*p) == func(*q)) + { + break; + } + } + if(q == update.end()) + { + result.push_back(*p); + } + } + } + return result; +} + +template<typename Dict> Dict +getDictUpdatedElts(const Dict& ldict, const Dict& rdict) +{ +#if defined(_MSC_VER) && (_MSC_VER < 1300) + return getDictUpdatedEltsWithEq(ldict, rdict, equal_to<Dict::mapped_type>()); +#else + return getDictUpdatedEltsWithEq(ldict, rdict, equal_to<typename Dict::mapped_type>()); +#endif +} + +template<typename EqFunc, typename Dict> Dict +getDictUpdatedEltsWithEq(const Dict& ldict, const Dict& rdict, EqFunc eq) +{ + Dict result; + for(typename Dict::const_iterator p = rdict.begin(); p != rdict.end(); ++p) + { + typename Dict::const_iterator q = ldict.find(p->first); + if(q == ldict.end() || !eq(p->second, q->second)) + { + result.insert(*p); + } + } + return result; +} + +template <typename Dict> Ice::StringSeq +getDictRemovedElts(const Dict& ldict, const Dict& rdict) +{ + Ice::StringSeq removed; + for(typename Dict::const_iterator p = ldict.begin(); p != ldict.end(); ++p) + { + if(rdict.find(p->first) == rdict.end()) + { + removed.push_back(p->first); + } + } + return removed; +} + +template <typename Dict> Dict +updateDictElts(const Dict& dict, const Dict& update, const Ice::StringSeq& remove) +{ + Dict result = dict; + for(Ice::StringSeq::const_iterator p = remove.begin(); p != remove.end(); ++p) + { + result.erase(*p); + } + for(typename Dict::const_iterator q = update.begin(); q != update.end(); ++q) + { + result[q->first] = q->second; + } + return result; +} + +} + +Resolver::Resolver(const ApplicationDescriptor& app, const Ice::CommunicatorPtr& communicator, bool enableWarning) : + _application(&app), + _communicator(communicator), + _escape(false), + _enableWarning(enableWarning), + _context("application `" + app.name + "'"), + _variables(app.variables), + _reserved(getReserved()), + _version(0) +{ + // + // Make sure the variables don't override reserved variables. + // + checkReserved("variable", _variables); + setReserved("application", app.name); + + // + // Some reserved variables which are ignored for now and will be + // substituted later. + // + _ignore.insert("node.os"); + _ignore.insert("node.hostname"); + _ignore.insert("node.release"); + _ignore.insert("node.version"); + _ignore.insert("node.machine"); + _ignore.insert("node.datadir"); + + for(StringStringDict::const_iterator v = _variables.begin(); v != _variables.end(); ++v) + { + if(v->first == "") + { + exception("empty variable name"); + } + } + + TemplateDescriptorDict::const_iterator t; + for(t = _application->serverTemplates.begin(); t != _application->serverTemplates.end(); ++t) + { + if(t->first == "") + { + exception("empty server template id"); + } + if(!t->second.descriptor) + { + exception("invalid server template `" + t->first + "': server definition is empty"); + } + + Ice::StringSeq params = t->second.parameters; + sort(params.begin(), params.end()); + Ice::StringSeq wdups = params; + Ice::StringSeq dups; + set_difference(wdups.begin(), wdups.end(), params.begin(), unique(params.begin(), params.end()), + back_inserter(dups)); + if(!dups.empty()) + { + dups.erase(unique(dups.begin(), dups.end()), dups.end()); + exception("invalid server template `" + t->first + "': duplicate parameters " + toString(dups)); + } + } + for(t = _application->serviceTemplates.begin(); t != _application->serviceTemplates.end(); ++t) + { + if(t->first == "") + { + exception("empty service template id"); + } + if(!t->second.descriptor) + { + exception("invalid service template `" + t->first + "': service definition is empty"); + } + Ice::StringSeq params = t->second.parameters; + sort(params.begin(), params.end()); + Ice::StringSeq wdups = params; + Ice::StringSeq dups; + set_difference(wdups.begin(), wdups.end(), params.begin(), unique(params.begin(), params.end()), + back_inserter(dups)); + if(!dups.empty()) + { + dups.erase(unique(dups.begin(), dups.end()), dups.end()); + exception("invalid server template `" + t->first + "': duplicate parameters " + toString(dups)); + } + } +} + +Resolver::Resolver(const Resolver& resolve, + const map<string, string>& values, + bool params) : + _application(resolve._application), + _communicator(resolve._communicator), + _escape(resolve._escape), + _enableWarning(resolve._enableWarning), + _context(resolve._context), + _variables(params ? resolve._variables : values), + _parameters(!params ? resolve._parameters : values), + _propertySets(resolve._propertySets), + _reserved(resolve._reserved), + _ignore(resolve._ignore), + _version(resolve._version) +{ + if(params) + { + checkReserved("parameter", values); + } + else + { + _variables.insert(resolve._variables.begin(), resolve._variables.end()); + checkReserved("variable", values); + } + + for(StringStringDict::const_iterator v = _variables.begin(); v != _variables.end(); ++v) + { + if(v->first == "") + { + exception("empty variable name"); + } + } +} + +Resolver::Resolver(const InternalNodeInfoPtr& info, const Ice::CommunicatorPtr& com) : + _application(0), + _communicator(com), + _escape(true), + _enableWarning(false), + _context("node `" + info->name + "'"), + _reserved(getReserved()), + _version(0) +{ + setReserved("node", info->name); + setReserved("node.os", info->os); + setReserved("node.hostname", info->hostname); + setReserved("node.release", info->release); + setReserved("node.version", info->version); + setReserved("node.machine", info->machine); + setReserved("node.datadir", info->dataDir); +} + +string +Resolver::operator()(const string& value, const string& name, bool allowEmpty) const +{ + try + { + string val; + try + { + val = substitute(value, true, true); + } + catch(const string& reason) + { + throw "invalid variable `" + value + "':\n " + reason; + } + catch(const char* reason) + { + throw "invalid variable `" + value + "':\n " + reason; + } + + if(!allowEmpty) + { + if(value.empty()) + { + throw "empty string"; + } + else if(val.empty()) + { + throw "the value of `" + value + "' is an empty string"; + } + } + return val; + } + catch(const string& reason) + { + exception("invalid value for attribute `" + name + "':\n" + reason); + } + catch(const char* reason) + { + exception("invalid value for attribute `" + name + "':\n" + reason); + } + return ""; // To prevent compiler warning. +} + +Ice::StringSeq +Resolver::operator()(const Ice::StringSeq& values, const string& name) const +{ + Ice::StringSeq result; + for(Ice::StringSeq::const_iterator p = values.begin(); p != values.end(); ++p) + { + result.push_back(operator()(*p, name)); + } + return result; +} + +DistributionDescriptor +Resolver::operator()(const DistributionDescriptor& desc) const +{ + DistributionDescriptor result; + result.icepatch = operator()(desc.icepatch, "IcePatch2 server proxy"); + result.directories = operator()(desc.directories, "distribution source directory"); + return result; +} + +PropertyDescriptorSeq +Resolver::operator()(const PropertyDescriptorSeq& properties, const string& name) const +{ + PropertyDescriptorSeq result; + for(PropertyDescriptorSeq::const_iterator q = properties.begin(); q != properties.end(); ++q) + { + PropertyDescriptor prop; + prop.name = operator()(q->name, name + " name"); + prop.value = operator()(q->value, name + " value"); + result.push_back(prop); + } + return result; +} + +PropertySetDescriptorDict +Resolver::operator()(const PropertySetDescriptorDict& propertySets) const +{ + PropertySetDescriptorDict result; + PropertySetDescriptorDict::const_iterator ps; + for(ps = propertySets.begin(); ps != propertySets.end(); ++ps) + { + PropertySetDescriptor desc; + desc.references = operator()(ps->second.references, "property set `" + ps->first + "' reference"); + desc.properties = operator()(ps->second.properties, "property set `" + ps->first + "' property"); + result.insert(make_pair(ps->first, desc)); + } + return result; +} + +ObjectDescriptorSeq +Resolver::operator()(const ObjectDescriptorSeq& objects, const string& type) const +{ + ObjectDescriptorSeq result; + for(ObjectDescriptorSeq::const_iterator q = objects.begin(); q != objects.end(); ++q) + { + ObjectDescriptor obj; + obj.type = operator()(q->type, type + " object type"); + obj.id = operator()(q->id, type + " object identity"); + result.push_back(obj); + } + return result; +} + +Ice::Identity +Resolver::operator()(const Ice::Identity& value, const string& name) const +{ + assert(_communicator); + string str = asId(_communicator->identityToString(value), name, false); + Ice::Identity id = _communicator->stringToIdentity(str); + if(id.name.empty()) + { + exception("invalid object identity `" + _communicator->identityToString(value) + "': name empty"); + } + return id; +} + +PropertySetDescriptor +Resolver::operator()(const PropertySetDescriptor& desc) const +{ + PropertySetDescriptor result; + result.properties = getProperties(desc.references); + PropertyDescriptorSeq props = operator()(desc.properties); + result.properties.insert(result.properties.end(), props.begin(), props.end()); + return result; +} + +string +Resolver::asInt(const string& value, const string& name) const +{ + string v = operator()(value, name); + if(!v.empty()) + { + string::size_type beg = v.find_first_not_of(' '); + string::size_type end = v.find_last_not_of(' '); + v = v.substr(beg == string::npos ? 0 : beg, end == string::npos ? v.length() - 1 : end - beg + 1); + + int val; + istringstream is(v); + if(!(is >> val) || !is.eof()) + { + exception("invalid value `" + value + "' for `" + name + "':\nnot an integer"); + } + + ostringstream os; + os << val; + v = os.str(); + } + return v; +} + +string +Resolver::asFloat(const string& value, const string& name) const +{ + string v = operator()(value, name); + if(!v.empty()) + { + string::size_type beg = v.find_first_not_of(' '); + string::size_type end = v.find_last_not_of(' '); + v = v.substr(beg == string::npos ? 0 : beg, end == string::npos ? v.length() - 1 : end - beg + 1); + + float val; + istringstream is(v); + if(!(is >> val) || !is.eof()) + { + exception("invalid value `" + value + "' for `" + name + "':\nnot a float"); + } + } + return v; +} + +string +Resolver::asId(const string& value, const string& name, bool allowEmpty) const +{ + try + { + if(!allowEmpty && value.empty()) + { + throw "empty string"; + } + + string val; + try + { + val = substitute(value, true, false); + } + catch(const string& reason) + { + throw "invalid variable `" + value + "':\n" + reason; + } + catch(const char* reason) + { + throw "invalid variable `" + value + "':\n" + reason; + } + + if(!allowEmpty && val.empty()) + { + throw "the value of `" + value + "' is an empty string"; + } + return val; + } + catch(const string& reason) + { + exception("invalid value for attribute `" + name + "':\n" + reason); + } + catch(const char* reason) + { + exception("invalid value for attribute `" + name + "':\n" + reason); + } + return ""; // To prevent compiler warning. +} + +void +Resolver::setReserved(const string& name, const string& value) +{ + assert(_reserved.find(name) != _reserved.end()); + _reserved[name] = value; +} + +void +Resolver::setContext(const string& context) +{ + try + { + _context = substitute(context, true, true); + } + catch(const string& reason) + { + exception(reason); + } + catch(const char* reason) + { + exception(reason); + } +} + +void +Resolver::addPropertySets(const PropertySetDescriptorDict& propertySets) +{ + PropertySetDescriptorDict oldPropertySets; + oldPropertySets.swap(_propertySets); + PropertySetDescriptorDict::const_iterator p; + for(p = propertySets.begin(); p != propertySets.end(); ++p) + { + if(!_propertySets.insert(*p).second) + { + exception("property set with id `" + p->first + "' is already defined at this scope"); + } + } + _propertySets.insert(oldPropertySets.begin(), oldPropertySets.end()); + + // + // Validate the new property set references. + // + for(p = propertySets.begin(); p != propertySets.end(); ++p) + { + getProperties(p->second.references); + } +} + +const PropertySetDescriptor& +Resolver::getPropertySet(const string& id) const +{ + PropertySetDescriptorDict::const_iterator p = _propertySets.find(id); + if(p == _propertySets.end()) + { + exception("invalid reference to property set, property set `" + id + "' doesn't exist"); + } + return p->second; +} + +PropertyDescriptorSeq +Resolver::getProperties(const Ice::StringSeq& references) const +{ + set<string> resolved; + return getProperties(references, resolved); +} + +void +Resolver::addIgnored(const string& name) +{ + _ignore.insert(name); +} + +void +Resolver::setVersion(const string& version) +{ + string v = operator()(version, "ice version"); + if(!v.empty()) + { + _version = getMMVersion(v); + if(_version < 0) + { + exception("invalid ice version: " + v); + } + else if(_version > ICE_INT_VERSION && warningEnabled()) + { + Ice::Warning out(_communicator->getLogger()); + out << "invalid ice version: " << _version << " is superior to the IceGrid "; + out << "registry version (" << ICE_STRING_VERSION << ")"; + } + } +} + +int +Resolver::getVersion() const +{ + return _version; +} + +void +Resolver::exception(const string& reason) const +{ + throw DeploymentException(_context + ":\n" + reason); +} + +TemplateDescriptor +Resolver::getServerTemplate(const string& tmpl) const +{ + assert(_application); + TemplateDescriptorDict::const_iterator p = _application->serverTemplates.find(tmpl); + if(p == _application->serverTemplates.end()) + { + throw DeploymentException("unknown server template `" + tmpl + "'"); + } + return p->second; +} + +TemplateDescriptor +Resolver::getServiceTemplate(const string& tmpl) const +{ + assert(_application); + TemplateDescriptorDict::const_iterator p = _application->serviceTemplates.find(tmpl); + if(p == _application->serviceTemplates.end()) + { + throw DeploymentException("unknown service template `" + tmpl + "'"); + } + return p->second; +} + +bool +Resolver::hasReplicaGroup(const string& id) const +{ + if(!_application) + { + // + // If we don't know the application descrpitor we assume that + // the replica group exists (this is possible if the resolver + // wasn't built from an application helper, that's the case if + // it's built from NodeCache just to resolve ${node.*} and + // ${session.*} variables. + // + return true; + } + ReplicaGroupDescriptorSeq::const_iterator p; + for(p = _application->replicaGroups.begin(); p != _application->replicaGroups.end(); ++p) + { + if(p->id == id) + { + return true; + } + } + return false; +} + +string +Resolver::substitute(const string& v, bool useParams, bool useIgnored) const +{ + string value(v); + string::size_type beg = 0; + string::size_type end = 0; + + while((beg = value.find("${", beg)) != string::npos) + { + if(beg > 0 && value[beg - 1] == '$') + { + string::size_type escape = beg - 1; + while(escape > 0 && value[escape - 1] == '$') + { + --escape; + } + + if((beg - escape) % 2) + { + if(_escape) + { + value.replace(escape, beg - escape, (beg - escape) / 2, '$'); + } + ++beg; + continue; + } + else + { + value.replace(escape, beg - escape, (beg - escape) / 2, '$'); + beg -= (beg - escape) / 2; + } + } + + end = value.find("}", beg); + if(end == string::npos) + { + throw "malformed variable name `" + value + "'"; + } + + // + // Get the name of the variable and get its value if the + // variable is not currently ignored (in which case we do + // nothing, the variable will be substituted later). If the + // name refered to a parameter we don't do any recursive + // substitution: the parameter value is computed at the point + // of definition. + // + string name = value.substr(beg + 2, end - beg - 2); + if(_ignore.find(name) != _ignore.end()) + { + if(useIgnored) + { + ++beg; + continue; + } + else + { + throw "use of the `" + name + "' variable is now allowed here"; + } + } + + bool param; + string val = getVariable(name, useParams, param); + if(!param) + { + val = substitute(val, false, useIgnored); // Recursive resolution + } + value.replace(beg, end - beg + 1, val); + beg += val.length(); + } + return value; +} + +string +Resolver::getVariable(const string& name, bool checkParams, bool& param) const +{ + // + // We first check the reserved variables, then the parameters if + // necessary and finally the variables. + // + param = false; + map<string, string>::const_iterator p = _reserved.find(name); + if(p != _reserved.end()) + { + if(p->second.empty()) + { + throw "undefined variable `" + name + "'"; + } + return p->second; + } + if(checkParams) + { + p = _parameters.find(name); + if(p != _parameters.end()) + { + param = true; + return p->second; + } + } + p = _variables.find(name); + if(p != _variables.end()) + { + return p->second; + } + + throw "undefined variable `" + name + "'"; + return ""; // To keep the compiler happy. +} + +PropertyDescriptorSeq +Resolver::getProperties(const Ice::StringSeq& references, set<string>& resolved) const +{ + PropertyDescriptorSeq properties; + for(Ice::StringSeq::const_iterator p = references.begin(); p != references.end(); ++p) + { + if(resolved.find(*p) != resolved.end()) + { + exception("detected circular dependency with property reference `" + *p + "'"); + } + + PropertySetDescriptor desc = getPropertySet(*p); + if(!desc.references.empty()) + { + resolved.insert(*p); + PropertyDescriptorSeq p = getProperties(desc.references, resolved); + properties.insert(properties.end(), p.begin(), p.end()); + } + + PropertyDescriptorSeq pds = operator()(desc.properties); + properties.insert(properties.end(), pds.begin(), pds.end()); + } + return properties; +} + +map<string, string> +Resolver::getReserved() +{ + // + // Allowed reserved variables (reserved variables can't be + // overrided, in this implementation an empty reserved variable is + // considered to be undefined (see getVariable)) + // + map<string, string> reserved; + reserved["application"] = ""; + reserved["node"] = ""; + reserved["node.os"] = ""; + reserved["node.hostname"] = ""; + reserved["node.release"] = ""; + reserved["node.version"] = ""; + reserved["node.machine"] = ""; + reserved["node.datadir"] = ""; + reserved["session.id"] = ""; + reserved["application.distrib"] = "${node.datadir}/distrib/${application}"; + reserved["server.distrib"] = "${node.datadir}/servers/${server}/distrib"; + reserved["server"] = ""; + reserved["service"] = ""; + return reserved; +} + +void +Resolver::checkReserved(const string& type, const map<string, string>& values) const +{ + for(map<string, string>::const_iterator p = values.begin(); p != values.end(); ++p) + { + if(_reserved.find(p->first) != _reserved.end()) + { + exception("invalid " + type + " `" + p->first + "': reserved variable name"); + } + } +} + +CommunicatorHelper::CommunicatorHelper(const CommunicatorDescriptorPtr& desc) : + _desc(desc) +{ +} + +bool +CommunicatorHelper::operator==(const CommunicatorHelper& helper) const +{ + if(_desc->ice_id() != helper._desc->ice_id()) + { + return false; + } + + if(_desc->description != helper._desc->description) + { + return false; + } + + if(set<AdapterDescriptor>(_desc->adapters.begin(), _desc->adapters.end()) != + set<AdapterDescriptor>(helper._desc->adapters.begin(), helper._desc->adapters.end())) + { + return false; + } + + if(_desc->propertySet != helper._desc->propertySet) + { + return false; + } + + if(set<DbEnvDescriptor>(_desc->dbEnvs.begin(), _desc->dbEnvs.end()) != + set<DbEnvDescriptor>(helper._desc->dbEnvs.begin(), helper._desc->dbEnvs.end())) + { + return false; + } + + if(_desc->logs != helper._desc->logs) + { + return false; + } + + return true; +} + +bool +CommunicatorHelper::operator!=(const CommunicatorHelper& helper) const +{ + return !operator==(helper); +} + +void +CommunicatorHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identity>& objectIds) const +{ + for(AdapterDescriptorSeq::const_iterator p = _desc->adapters.begin(); p != _desc->adapters.end(); ++p) + { + if(!p->id.empty()) + { + adapterIds.insert(p->id); + } + + set<Ice::Identity> ids; + ObjectDescriptorSeq::const_iterator q; + for(q = p->objects.begin(); q != p->objects.end(); ++q) + { + ids.insert(q->id); + objectIds.insert(q->id); + } + for(q = p->allocatables.begin(); q != p->allocatables.end(); ++q) + { + if(ids.find(q->id) == ids.end()) + { + objectIds.insert(q->id); + } + else + { + ids.erase(q->id); + } + } + } +} + +void +CommunicatorHelper::getReplicaGroups(set<string>& replicaGroups) const +{ + for(AdapterDescriptorSeq::const_iterator p = _desc->adapters.begin(); p != _desc->adapters.end(); ++p) + { + if(!p->replicaGroupId.empty()) + { + replicaGroups.insert(p->replicaGroupId); + } + } +} + +void +CommunicatorHelper::instantiateImpl(const CommunicatorDescriptorPtr& instance, const Resolver& resolve) const +{ + instance->description = resolve(_desc->description, "description"); + instance->propertySet = resolve(_desc->propertySet); + + for(AdapterDescriptorSeq::const_iterator p = _desc->adapters.begin(); p != _desc->adapters.end(); ++p) + { + AdapterDescriptor adapter; + adapter.name = resolve(p->name, "object adapter name", false); + adapter.description = resolve(p->description, "object adapter description"); + adapter.id = resolve.asId(p->id, "object adapter id"); + adapter.registerProcess = p->registerProcess; + adapter.serverLifetime = p->serverLifetime; + adapter.replicaGroupId = resolve.asId(p->replicaGroupId, "object adapter replica group id", true); + + // + // Don't check for unknown replica groups here. This check is + // instead done by the database before the application is + // added. It's legal for an OA to refer to a replica group + // from another application. + // + //if(!adapter.replicaGroupId.empty() && !resolve.hasReplicaGroup(adapter.replicaGroupId)) + //{ + //resolve.exception("unknown replica group `" + adapter.replicaGroupId + "'"); + //} + + adapter.priority = resolve.asInt(p->priority, "object adapter priority"); + adapter.objects = resolve(p->objects, "well-known"); + adapter.allocatables = resolve(p->allocatables, "allocatable"); + instance->adapters.push_back(adapter); + + // + // Make sure the endpoints are defined. + // + if(IceGrid::getProperty(instance->propertySet.properties, adapter.name + ".Endpoints").empty()) + { + resolve.exception("invalid endpoints for adapter `" + adapter.name + "': empty string"); + } + } + + for(DbEnvDescriptorSeq::const_iterator s = _desc->dbEnvs.begin(); s != _desc->dbEnvs.end(); ++s) + { + DbEnvDescriptor dbEnv; + dbEnv.name = resolve(s->name, "database environment name", false); + dbEnv.description = resolve(s->description, "database environment description"); + dbEnv.dbHome = resolve(s->dbHome, "database environment home directory"); + dbEnv.properties = resolve(s->properties, "database environment property"); + instance->dbEnvs.push_back(dbEnv); + } + + for(Ice::StringSeq::const_iterator l = _desc->logs.begin(); l != _desc->logs.end(); ++l) + { + instance->logs.push_back(resolve(*l, "log path", false)); + } +} + +void +CommunicatorHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const +{ + if(!_desc->description.empty()) + { + out << nl << "description"; + out << sb; + out << nl << _desc->description; + out << eb; + } + set<string> hiddenProperties; + { + for(DbEnvDescriptorSeq::const_iterator p = _desc->dbEnvs.begin(); p != _desc->dbEnvs.end(); ++p) + { + printDbEnv(out, *p); + } + } + { + for(AdapterDescriptorSeq::const_iterator p = _desc->adapters.begin(); p != _desc->adapters.end(); ++p) + { + hiddenProperties.insert(p->name + ".Endpoints"); + printObjectAdapter(communicator, out, *p); + } + } + { + for(Ice::StringSeq::const_iterator p = _desc->logs.begin(); p != _desc->logs.end(); ++p) + { + out << nl << "log `" << *p << "'"; + } + } + if(!_desc->propertySet.properties.empty() || !_desc->propertySet.references.empty()) + { + out << nl << "properties"; + out << sb; + if(!_desc->propertySet.references.empty()) + { + out << nl << "references = " << toString(_desc->propertySet.references); + } + PropertyDescriptorSeq::const_iterator q; + for(q = _desc->propertySet.properties.begin(); q != _desc->propertySet.properties.end(); ++q) + { + if(hiddenProperties.find(q->name) == hiddenProperties.end()) + { + out << nl << q->name << " = `" << q->value << "'"; + } + } + out << eb; + } +} + +void +CommunicatorHelper::printDbEnv(Output& out, const DbEnvDescriptor& dbEnv) const +{ + out << nl << "database environment `" << dbEnv.name << "'"; + if(!dbEnv.dbHome.empty() || !dbEnv.properties.empty() || !dbEnv.description.empty()) + { + out << sb; + if(!dbEnv.dbHome.empty()) + { + out << nl << "home = `" << dbEnv.dbHome << "'"; + } + if(!dbEnv.description.empty()) + { + out << nl << "description = `" << dbEnv.description << "'"; + } + if(!dbEnv.properties.empty()) + { + out << nl << "properties"; + out << sb; + for(PropertyDescriptorSeq::const_iterator p = dbEnv.properties.begin(); p != dbEnv.properties.end(); ++p) + { + out << nl << p->name << " = `" << p->value << "'"; + } + out << eb; + } + out << eb; + } +} + +void +CommunicatorHelper::printObjectAdapter(const Ice::CommunicatorPtr& communicator, + Output& out, + const AdapterDescriptor& adapter) const +{ + out << nl << "adapter `" << adapter.name << "'"; + out << sb; + if(!adapter.id.empty()) + { + out << nl << "id = `" << adapter.id << "'"; + } + if(!adapter.replicaGroupId.empty()) + { + out << nl << "replica group id = `" << adapter.replicaGroupId << "'"; + } + if(!adapter.priority.empty()) + { + out << nl << "priority = `" << adapter.priority << "'"; + } + + string endpoints = getProperty(adapter.name + ".Endpoints"); + if(!endpoints.empty()) + { + out << nl << "endpoints = `" << endpoints << "'"; + } + out << nl << "register process = `" << (adapter.registerProcess ? "true" : "false") << "'"; + out << nl << "server lifetime = `" << (adapter.serverLifetime ? "true" : "false") << "'"; + ObjectDescriptorSeq::const_iterator p; + for(p = adapter.objects.begin(); p != adapter.objects.end(); ++p) + { + out << nl << "well-known object"; + out << sb; + out << nl << "identity = `" << communicator->identityToString(p->id) << "' "; + if(!p->type.empty()) + { + out << nl << "type = `" << p->type << "'"; + } + out << eb; + } + for(p = adapter.allocatables.begin(); p != adapter.allocatables.end(); ++p) + { + out << nl << "allocatable"; + out << sb; + out << nl << "identity = `" << communicator->identityToString(p->id) << "' "; + if(!p->type.empty()) + { + out << nl << "type = `" << p->type << "'"; + } + out << eb; + } + if(!adapter.description.empty()) + { + out << nl << "description = `" << adapter.description << "'"; + } + out << eb; +} + +string +CommunicatorHelper::getProperty(const string& name) const +{ + return IceGrid::getProperty(_desc->propertySet.properties, name); +} + +ServiceHelper::ServiceHelper(const ServiceDescriptorPtr& descriptor) : + CommunicatorHelper(descriptor), + _desc(descriptor) +{ +} + +bool +ServiceHelper::operator==(const CommunicatorHelper& h) const +{ + const ServiceHelper* helper = dynamic_cast<const ServiceHelper*>(&h); + if(!helper || !CommunicatorHelper::operator==(h)) + { + return false; + } + + if(_desc->name != helper->_desc->name) + { + return false; + } + + if(_desc->entry != helper->_desc->entry) + { + return false; + } + + return true; +} + +bool +ServiceHelper::operator!=(const CommunicatorHelper& helper) const +{ + return !operator==(helper); +} + +ServiceDescriptorPtr +ServiceHelper::getDescriptor() const +{ + return _desc; +} + +ServiceDescriptorPtr +ServiceHelper::instantiate(const Resolver& resolver, const PropertyDescriptorSeq& props, + const PropertySetDescriptorDict& serviceProps) const +{ + ServiceDescriptorPtr service = new ServiceDescriptor(); + instantiateImpl(service, resolver, props, serviceProps); + return service; +} + +void +ServiceHelper::instantiateImpl(const ServiceDescriptorPtr& instance, + const Resolver& resolve, + const PropertyDescriptorSeq& props, + const PropertySetDescriptorDict& serviceProps) const +{ + CommunicatorHelper::instantiateImpl(instance, resolve); + instance->name = resolve(_desc->name, "name", false); + instance->entry = resolve(_desc->entry, "entry", false); + instance->propertySet.properties.insert(instance->propertySet.properties.end(), props.begin(), props.end()); + PropertySetDescriptorDict::const_iterator p = serviceProps.find(instance->name); + if(p != serviceProps.end()) + { + instance->propertySet.properties.insert(instance->propertySet.properties.end(), + p->second.properties.begin(), + p->second.properties.end()); + } +} + +void +ServiceHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const +{ + out << "service `" + _desc->name + "'"; + out << sb; + out << nl << "entry = `" << _desc->entry << "'"; + CommunicatorHelper::print(communicator, out); + out << eb; +} + +ServerHelper::ServerHelper(const ServerDescriptorPtr& descriptor) : + CommunicatorHelper(descriptor), + _desc(descriptor) +{ +} + +bool +ServerHelper::operator==(const CommunicatorHelper& h) const +{ + const ServerHelper* helper = dynamic_cast<const ServerHelper*>(&h); + if(!helper || !CommunicatorHelper::operator==(h)) + { + return false; + } + + if(_desc->id != helper->_desc->id) + { + return false; + } + + if(_desc->exe != helper->_desc->exe) + { + return false; + } + + if(_desc->iceVersion != helper->_desc->iceVersion) + { + return false; + } + + if(_desc->pwd != helper->_desc->pwd) + { + return false; + } + + if(set<string>(_desc->options.begin(), _desc->options.end()) != + set<string>(helper->_desc->options.begin(), helper->_desc->options.end())) + { + return false; + } + + if(set<string>(_desc->envs.begin(), _desc->envs.end()) != + set<string>(helper->_desc->envs.begin(), helper->_desc->envs.end())) + { + return false; + } + + if(_desc->activation != helper->_desc->activation) + { + return false; + } + + if(_desc->activationTimeout != helper->_desc->activationTimeout) + { + return false; + } + + if(_desc->deactivationTimeout != helper->_desc->deactivationTimeout) + { + return false; + } + + if(_desc->distrib != helper->_desc->distrib) + { + return false; + } + + if(_desc->allocatable != helper->_desc->allocatable) + { + return false; + } + + if(_desc->user != helper->_desc->user) + { + return false; + } + + return true; +} + +bool +ServerHelper::operator!=(const CommunicatorHelper& helper) const +{ + return !operator==(helper); +} + +ServerDescriptorPtr +ServerHelper::getDescriptor() const +{ + return _desc; +} + +ServerDescriptorPtr +ServerHelper::instantiate(const Resolver& resolver, + const PropertyDescriptorSeq& props, + const PropertySetDescriptorDict& serviceProps) const +{ + if(!serviceProps.empty()) + { + resolver.exception("service property sets are only allowed in IceBox server instances"); + } + + ServerDescriptorPtr server = new ServerDescriptor(); + instantiateImpl(server, resolver, props); + return server; +} + +void +ServerHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const +{ + print(communicator, out, ServerInfo()); +} + +void +ServerHelper::print(const Ice::CommunicatorPtr& communicator, Output& out, const ServerInfo& info) const +{ + out << "server `" + _desc->id + "'"; + out << sb; + printImpl(communicator, out, info); + out << eb; +} + +void +ServerHelper::printImpl(const Ice::CommunicatorPtr& communicator, Output& out, const ServerInfo& info) const +{ + if(!info.application.empty()) + { + out << nl << "application = `" << info.application << "'"; + out << nl << "application uuid = `" << info.uuid << "'"; + out << nl << "application revision = `" << info.revision << "'"; + } + if(!info.node.empty()) + { + out << nl << "node = `" << info.node << "'"; + } + if(!info.sessionId.empty()) + { + out << nl << "session id = `" << info.sessionId << "'"; + } + out << nl << "exe = `" << _desc->exe << "'"; + + if(!_desc->iceVersion.empty()) + { + out << nl << "ice version = `" << _desc->iceVersion << "'"; + } + + if(!_desc->pwd.empty()) + { + out << nl << "pwd = `" << _desc->pwd << "'"; + } + out << nl << "activation = `" << _desc->activation << "'"; + if(!_desc->activationTimeout.empty() && _desc->activationTimeout != "0") + { + out << nl << "activationTimeout = `" << _desc->activationTimeout << "'"; + } + if(!_desc->deactivationTimeout.empty() && _desc->deactivationTimeout != "0") + { + out << nl << "deactivationTimeout = `" << _desc->deactivationTimeout << "'"; + } + if(!_desc->user.empty()) + { + out << nl << "user = `" << _desc->user << "'"; + } + if(!_desc->applicationDistrib) + { + out << nl << "application distribution = `false'"; + } + if(!_desc->options.empty()) + { + out << nl << "options = `" << toString(_desc->options) << "'"; + } + if(!_desc->envs.empty()) + { + out << nl << "envs = `" << toString(_desc->envs) << "'"; + } + if(!_desc->distrib.icepatch.empty()) + { + out << nl << "distribution"; + out << sb; + out << nl << "proxy = `" << _desc->distrib.icepatch << "'"; + if(!_desc->distrib.directories.empty()) + { + out << nl << "directories = `" << toString(_desc->distrib.directories) << "'"; + } + out << eb; + } + CommunicatorHelper::print(communicator, out); +} + +void +ServerHelper::instantiateImpl(const ServerDescriptorPtr& instance, + const Resolver& resolve, + const PropertyDescriptorSeq& props) const +{ + CommunicatorHelper::instantiateImpl(instance, resolve); + + instance->id = resolve.asId(_desc->id, "id", false); + instance->exe = resolve(_desc->exe, "executable", false); + instance->iceVersion = resolve(_desc->iceVersion, "ice version"); + instance->pwd = resolve(_desc->pwd, "working directory path"); + instance->activation = resolve(_desc->activation, "activation"); + instance->applicationDistrib = _desc->applicationDistrib; + instance->allocatable = _desc->allocatable; + instance->user = resolve(_desc->user, "user"); + if(!instance->activation.empty() && + instance->activation != "manual" && + instance->activation != "on-demand" && + instance->activation != "always" && + instance->activation != "session") + { + resolve.exception("unknown activation `" + instance->activation + "'"); + } + instance->activationTimeout = resolve.asInt(_desc->activationTimeout, "activation timeout"); + instance->deactivationTimeout = resolve.asInt(_desc->deactivationTimeout, "deactivation timeout"); + instance->options = resolve(_desc->options, "option"); + instance->envs = resolve(_desc->envs, "environment variable"); + instance->distrib = resolve(_desc->distrib); + instance->propertySet.properties.insert(instance->propertySet.properties.end(), props.begin(), props.end()); +} + +IceBoxHelper::IceBoxHelper(const IceBoxDescriptorPtr& descriptor) : + ServerHelper(descriptor), + _desc(descriptor) +{ + for(ServiceInstanceDescriptorSeq::const_iterator p = _desc->services.begin(); p != _desc->services.end(); ++p) + { + _services.push_back(ServiceInstanceHelper(*p)); + } +} + +bool +IceBoxHelper::operator==(const CommunicatorHelper& h) const +{ + const IceBoxHelper* helper = dynamic_cast<const IceBoxHelper*>(&h); + if(!helper || !ServerHelper::operator==(h)) + { + return false; + } + + if(_services != helper->_services) + { + return false; + } + + return true; +} + +bool +IceBoxHelper::operator!=(const CommunicatorHelper& helper) const +{ + return !operator==(helper); +} + +ServerDescriptorPtr +IceBoxHelper::instantiate(const Resolver& resolver, + const PropertyDescriptorSeq& props, + const PropertySetDescriptorDict& serviceProps) const +{ + IceBoxDescriptorPtr iceBox = new IceBoxDescriptor(); + instantiateImpl(iceBox, resolver, props, serviceProps); + return iceBox; +} + +void +IceBoxHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identity>& objectIds) const +{ + CommunicatorHelper::getIds(adapterIds, objectIds); + for(vector<ServiceInstanceHelper>::const_iterator p = _services.begin(); p != _services.end(); ++p) + { + p->getIds(adapterIds, objectIds); + } +} + +void +IceBoxHelper::getReplicaGroups(set<string>& replicaGroups) const +{ + CommunicatorHelper::getReplicaGroups(replicaGroups); + for(vector<ServiceInstanceHelper>::const_iterator p = _services.begin(); p != _services.end(); ++p) + { + p->getReplicaGroups(replicaGroups); + } +} + +void +IceBoxHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const +{ + print(communicator, out, ServerInfo()); +} + +void +IceBoxHelper::print(const Ice::CommunicatorPtr& communicator, Output& out, const ServerInfo& info) const +{ + out << "icebox `" + _desc->id + "'"; + out << sb; + + string endpoints = getProperty("IceBox.ServiceManager.Endpoints"); + out << nl << "service manager endpoints = `" << endpoints << "'"; + printImpl(communicator, out, info); + out << nl << "services"; + out << sb; + for(ServiceInstanceDescriptorSeq::const_iterator p = _desc->services.begin(); p != _desc->services.end(); ++p) + { + assert(p->descriptor); + out << nl << p->descriptor->name; + } + out << eb; + out << eb; +} + +void +IceBoxHelper::instantiateImpl(const IceBoxDescriptorPtr& instance, + const Resolver& resolver, + const PropertyDescriptorSeq& props, + const PropertySetDescriptorDict& serviceProps) const +{ + ServerHelper::instantiateImpl(instance, resolver, props); + set<string> serviceNames; + for(vector<ServiceInstanceHelper>::const_iterator p = _services.begin(); p != _services.end(); ++p) + { + ServiceInstanceDescriptor desc = p->instantiate(resolver, serviceProps); + assert(desc.descriptor); + serviceNames.insert(desc.descriptor->name); + instance->services.push_back(desc); + } + for(PropertySetDescriptorDict::const_iterator q = serviceProps.begin(); q != serviceProps.end(); ++q) + { + if(serviceNames.find(q->first) == serviceNames.end()) + { + resolver.exception("invalid service property set: service `" + q->first + "' doesn't exist"); + } + } +} + +map<string, string> +InstanceHelper::instantiateParams(const Resolver& resolve, + const string& tmpl, + const map<string, string>& parameters, + const vector<string>& requiredParameters, + const map<string, string>& defaults) const +{ + map<string, string> params; + + set<string> required(requiredParameters.begin(), requiredParameters.end()); + set<string> unknown; + for(map<string, string>::const_iterator p = parameters.begin(); p != parameters.end(); ++p) + { + if(required.find(p->first) == required.end()) + { + unknown.insert(p->first); + } + params.insert(make_pair(p->first, resolve(p->second, "parameter `" + p->first + "'"))); + } + if(!unknown.empty()) + { + ostringstream os; + os << "unknown parameters when instantiating `" + tmpl + "' template: "; + copy(unknown.begin(), unknown.end(), ostream_iterator<string>(os, " ")); + resolve.exception(os.str()); + } + + set<string> missingParams; + for(set<string>::const_iterator q = required.begin(); q != required.end(); ++q) + { + if(params.find(*q) == params.end()) + { + map<string, string>::const_iterator r = defaults.find(*q); + if(r == defaults.end()) + { + missingParams.insert(*q); + } + else + { + params.insert(make_pair(r->first, resolve(r->second, "default parameter `" + r->first + "'"))); + } + } + } + if(!missingParams.empty()) + { + ostringstream os; + os << "undefined parameters when instantiating `" + tmpl + "' template: "; + copy(missingParams.begin(), missingParams.end(), ostream_iterator<string>(os, " ")); + resolve.exception(os.str()); + } + + return params; +} + +ServiceInstanceHelper::ServiceInstanceHelper(const ServiceInstanceDescriptor& desc) : + _def(desc) +{ + // + // If the service instance is not a template instance, its + // descriptor must be set and contain the definition of the + // service. + // + if(_def._cpp_template.empty() && !_def.descriptor) + { + throw DeploymentException("invalid service instance: no template defined"); + } + + if(_def.descriptor) + { + _service = ServiceHelper(_def.descriptor); + } +} + +bool +ServiceInstanceHelper::operator==(const ServiceInstanceHelper& helper) const +{ + if(_def._cpp_template.empty()) + { + return _service == helper._service; + } + else + { + return _def._cpp_template == helper._def._cpp_template && + _def.parameterValues == helper._def.parameterValues && + _def.propertySet == helper._def.propertySet; + } +} + +bool +ServiceInstanceHelper::operator!=(const ServiceInstanceHelper& helper) const +{ + return !operator==(helper); +} + +ServiceInstanceDescriptor +ServiceInstanceHelper::instantiate(const Resolver& resolve, const PropertySetDescriptorDict& serviceProps) const +{ + ServiceHelper def = _service; + std::map<std::string, std::string> parameterValues; + if(!def.getDescriptor()) + { + assert(!_def._cpp_template.empty()); + TemplateDescriptor tmpl = resolve.getServiceTemplate(_def._cpp_template); + def = ServiceHelper(ServiceDescriptorPtr::dynamicCast(tmpl.descriptor)); + parameterValues = instantiateParams(resolve, + _def._cpp_template, + _def.parameterValues, + tmpl.parameters, + tmpl.parameterDefaults); + } + + // + // Setup the resolver. + // + Resolver svcResolve(resolve, parameterValues, !_service.getDescriptor()); + svcResolve.setReserved("service", svcResolve(def.getDescriptor()->name, "service name", false)); + svcResolve.setContext("service `${service}' from server `${server}'"); + + // + // Instantiate the service instance. + // + ServiceInstanceDescriptor desc; + desc.descriptor = def.instantiate(svcResolve, svcResolve(_def.propertySet).properties, serviceProps); + + // + // NOTE: We can't keep the following attributes in the service + // instance otherwise the instance comparison would be based on + // the template + parameters which would be wrong (if the template + // changed the instance also changed.) + // + //desc._cpp_template = _template; + //desc.parameterValues = _parameters; + return desc; +} + +void +ServiceInstanceHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identity>& objectIds) const +{ + assert(_service.getDescriptor()); + _service.getIds(adapterIds, objectIds); +} + +void +ServiceInstanceHelper::getReplicaGroups(set<string>& replicaGroups) const +{ + assert(_service.getDescriptor()); + _service.getReplicaGroups(replicaGroups); +} + +void +ServiceInstanceHelper::print(const Ice::CommunicatorPtr& communicator, Output& out) const +{ + if(_service.getDescriptor()) + { + _service.print(communicator, out); + } + else + { + assert(!_def._cpp_template.empty()); + out << "service instance"; + out << sb; + out << nl << "template = `" << _def._cpp_template << "'"; + out << nl << "parameters"; + out << sb; + for(StringStringDict::const_iterator p = _def.parameterValues.begin(); p != _def.parameterValues.end(); ++p) + { + out << nl << p->first << " = `" << p->second << "'"; + } + out << eb; + out << eb; + } +} + +ServerInstanceHelper::ServerInstanceHelper(const ServerInstanceDescriptor& desc, + const Resolver& resolve, + bool instantiate) : + _def(desc) +{ + init(0, resolve, instantiate); +} + +ServerInstanceHelper::ServerInstanceHelper(const ServerDescriptorPtr& definition, + const Resolver& resolve, + bool instantiate) : + _def(ServerInstanceDescriptor()) +{ + init(definition, resolve, instantiate); +} + +void +ServerInstanceHelper::init(const ServerDescriptorPtr& definition, const Resolver& resolve, bool instantiate) +{ + // + // Get the server definition if it's not provided. + // + ServerDescriptorPtr def = definition; + std::map<std::string, std::string> parameterValues; + if(!def) + { + if(_def._cpp_template.empty()) + { + resolve.exception("invalid server instance: template is not defined"); + } + + // + // Get the server definition and the template property sets. + // + TemplateDescriptor tmpl = resolve.getServerTemplate(_def._cpp_template); + def = ServerDescriptorPtr::dynamicCast(tmpl.descriptor); + parameterValues = instantiateParams(resolve, + _def._cpp_template, + _def.parameterValues, + tmpl.parameters, + tmpl.parameterDefaults); + } + assert(def); + + // + // Setup the resolver. + // + Resolver svrResolve(resolve, parameterValues, true); + svrResolve.setReserved("server", svrResolve.asId(def->id, "server id", false)); + svrResolve.setContext("server `${server}'"); + svrResolve.setVersion(def->iceVersion); + _id = svrResolve("${server}"); + + // + // Set the server definition. + // + _serverDefinition = createHelper(def); + + if(!instantiate) + { + return; // We're done. + } + + // + // Ignore undefined session.id variable if the activation mode is + // 'session', it will get defined when the server is allocated. + // + if(svrResolve(def->activation, "server activation", true) == "session") + { + svrResolve.addIgnored("session.id"); + } + + // + // Instantiate the server instance definition (we use the server + // resolver above, so using parameters in properties is possible). + // + if(!_def._cpp_template.empty()) + { + _instance._cpp_template = _def._cpp_template; + _instance.parameterValues = parameterValues; + _instance.propertySet = svrResolve(_def.propertySet); + for(PropertySetDescriptorDict::const_iterator p = _def.servicePropertySets.begin(); + p != _def.servicePropertySets.end(); ++p) + { + _instance.servicePropertySets.insert(make_pair(svrResolve(p->first), svrResolve(p->second))); + } + } + + // + // Instantiate the server definition. + // + ServerDescriptorPtr inst = _serverDefinition->instantiate(svrResolve, _instance.propertySet.properties, + _instance.servicePropertySets); + _serverInstance = createHelper(inst); +} + +bool +ServerInstanceHelper::operator==(const ServerInstanceHelper& helper) const +{ + if(_def._cpp_template.empty()) + { + return *_serverDefinition == *helper._serverDefinition; + } + else + { + return _def._cpp_template == helper._def._cpp_template && + _def.parameterValues == helper._def.parameterValues && + _def.propertySet == helper._def.propertySet && + _def.servicePropertySets == helper._def.servicePropertySets; + } +} + +bool +ServerInstanceHelper::operator!=(const ServerInstanceHelper& helper) const +{ + return !operator==(helper); +} + +string +ServerInstanceHelper::getId() const +{ + return _id; +} + +ServerInstanceDescriptor +ServerInstanceHelper::getDefinition() const +{ + assert(!_def._cpp_template.empty()); + return _def; +} + +ServerInstanceDescriptor +ServerInstanceHelper::getInstance() const +{ + assert(!_def._cpp_template.empty() && !_instance._cpp_template.empty()); + return _instance; +} + +ServerDescriptorPtr +ServerInstanceHelper::getServerDefinition() const +{ + assert(_def._cpp_template.empty()); + return _serverDefinition->getDescriptor(); +} + +ServerDescriptorPtr +ServerInstanceHelper::getServerInstance() const +{ + assert(_serverInstance); + return _serverInstance->getDescriptor(); +} + +void +ServerInstanceHelper::getIds(multiset<string>& adapterIds, multiset<Ice::Identity>& objectIds) const +{ + assert(_serverInstance); + _serverInstance->getIds(adapterIds, objectIds); +} + +void +ServerInstanceHelper::getReplicaGroups(set<string>& replicaGroups) const +{ + assert(_serverInstance); + _serverInstance->getReplicaGroups(replicaGroups); +} + +NodeHelper::NodeHelper(const string& name, + const NodeDescriptor& descriptor, + const Resolver& appResolve, + bool instantiate) : + _name(name), + _def(descriptor), + _instantiated(instantiate) +{ + if(_name.empty()) + { + appResolve.exception("invalid node: empty name"); + } + + Resolver resolve(appResolve, _def.variables, false); + resolve.setReserved("node", _name); + resolve.setContext("node `" + _name + "'"); + + if(instantiate) + { + // + // Instantiate the node definition. + // + _instance.variables = _def.variables; + _instance.loadFactor = resolve.asFloat(_def.loadFactor, "load factor"); + _instance.description = resolve(_def.description, "description"); + _instance.propertySets = resolve(_def.propertySets); + + // + // Set the named property sets on the resolver. We use the + // instantiated named property sets here -- named property sets + // must be fully definied at the node level. + // + resolve.addPropertySets(_instance.propertySets); + } + + ServerInstanceDescriptorSeq::const_iterator p; + for(p = _def.serverInstances.begin(); p != _def.serverInstances.end(); ++p) + { + ServerInstanceHelper helper(*p, resolve, instantiate); + if(!_serverInstances.insert(make_pair(helper.getId(), helper)).second) + { + resolve.exception("duplicate server `" + helper.getId() + "' in node `" + _name + "'"); + } + if(instantiate) + { + _instance.serverInstances.push_back(helper.getInstance()); + } + } + + ServerDescriptorSeq::const_iterator q; + for(q = _def.servers.begin(); q != _def.servers.end(); ++q) + { + ServerInstanceHelper helper(*q, resolve, instantiate); + if(!_servers.insert(make_pair(helper.getId(), helper)).second) + { + resolve.exception("duplicate server `" + helper.getId() + "' in node `" + _name + "'"); + } + if(instantiate) + { + _instance.servers.push_back(helper.getServerInstance()); + } + } +} + +bool +NodeHelper::operator==(const NodeHelper& helper) const +{ + if(_def.variables != helper._def.variables) + { + return false; + } + + if(_serverInstances != helper._serverInstances) + { + return false; + } + + if(_servers != helper._servers) + { + return false; + } + + if(_def.loadFactor != helper._def.loadFactor) + { + return false; + } + + if(_def.description != helper._def.description) + { + return false; + } + + if(_def.propertySets != helper._def.propertySets) + { + return false; + } + + return true; +} + +bool +NodeHelper::operator!=(const NodeHelper& helper) const +{ + return !operator==(helper); +} + +NodeUpdateDescriptor +NodeHelper::diff(const NodeHelper& helper) const +{ + assert(_name == helper._name); + + NodeUpdateDescriptor update; + + update.name = _name; + if(_def.loadFactor != helper._def.loadFactor) + { + update.loadFactor = new BoxedString(_def.loadFactor); + } + + if(_def.description != helper._def.description) + { + update.description = new BoxedString(_def.description); + } + + update.variables = getDictUpdatedElts(helper._def.variables, _def.variables); + update.removeVariables = getDictRemovedElts(helper._def.variables, _def.variables); + + update.propertySets = getDictUpdatedElts(helper._def.propertySets, _def.propertySets); + update.removePropertySets = getDictRemovedElts(helper._def.propertySets, _def.propertySets); + + ServerInstanceHelperDict updated = getDictUpdatedElts(helper._serverInstances, _serverInstances); + for(ServerInstanceHelperDict::const_iterator p = updated.begin(); p != updated.end(); ++p) + { + update.serverInstances.push_back(p->second.getDefinition()); + } + update.removeServers = getDictRemovedElts(helper._serverInstances, _serverInstances); + + updated = getDictUpdatedElts(helper._servers, _servers); + for(ServerInstanceHelperDict::const_iterator q = updated.begin(); q != updated.end(); ++q) + { + update.servers.push_back(q->second.getServerDefinition()); + } + Ice::StringSeq removed = getDictRemovedElts(helper._servers, _servers); + update.removeServers.insert(update.removeServers.end(), removed.begin(), removed.end()); + return update; +} + +NodeDescriptor +NodeHelper::update(const NodeUpdateDescriptor& update, const Resolver& appResolve) const +{ + NodeDescriptor def; + assert(update.name == _name); + + // + // Update the variables, property sets, load factor, description. + // + def.variables = updateDictElts(_def.variables, update.variables, update.removeVariables); + def.propertySets = updateDictElts(_def.propertySets, update.propertySets, update.removePropertySets); + def.loadFactor = update.loadFactor ? update.loadFactor->value : _def.loadFactor; + def.description = update.description ? update.description->value : _def.description; + + // + // NOTE: It's important to create the resolver *after* updating + // the node variables! + // + Resolver resolve(appResolve, def.variables, false); + resolve.setReserved("node", _name); + resolve.setContext("node `" + _name + "'"); + + // + // Update the node servers and server instances. The update is in 2 steps: + // + // * first we instantiate the servers from the update descriptor. + // * then we add the servers from the node which were not updated or removed. + // + + ServerInstanceHelperDict::const_iterator r; + + set<string> added; + set<string> removed(update.removeServers.begin(), update.removeServers.end()); + + ServerInstanceDescriptorSeq::const_iterator q; + for(q = update.serverInstances.begin(); q != update.serverInstances.end(); ++q) + { + ServerInstanceHelper helper(*q, resolve, false); + if(!added.insert(helper.getId()).second) + { + resolve.exception("duplicate server `" + helper.getId() + "' in node `" + _name + "'"); + } + def.serverInstances.push_back(helper.getDefinition()); + } + for(r = _serverInstances.begin(); r != _serverInstances.end(); ++r) + { + if(removed.find(r->first) != removed.end() || added.find(r->first) != added.end()) + { + continue; + } + + // + // Re-instantiate the server. Make sure the server ID didn't + // change, if the ID of a server changes the update descriptor + // has to remove the server and add an update entry for it. + // + ServerInstanceHelper helper(r->second.getDefinition(), resolve, false); + if(helper.getId() != r->first) + { + resolve.exception("invalid update in node `" + _name + "':\n" + "server instance id `" + r->first + + "' changed to `" + helper.getId() + "'"); + } + def.serverInstances.push_back(helper.getDefinition()); + } + + added.clear(); + for(ServerDescriptorSeq::const_iterator s = update.servers.begin(); s != update.servers.end(); ++s) + { + ServerInstanceHelper helper(*s, resolve, false); + if(!added.insert(helper.getId()).second) + { + resolve.exception("duplicate server `" + helper.getId() + "' in node `" + _name + "'"); + } + def.servers.push_back(helper.getServerDefinition()); + } + for(r = _servers.begin(); r != _servers.end(); ++r) + { + if(removed.find(r->first) != removed.end() || added.find(r->first) != added.end()) + { + continue; + } + + // + // Re-instantiate the server. Make sure the server ID didn't + // change, if the ID of a server changes the update descriptor + // has to remove the server and add an update entry for it. + // + ServerInstanceHelper helper(r->second.getServerDefinition(), resolve, false); + if(helper.getId() != r->first) + { + resolve.exception("invalid update in node `" + _name + "':\nserver instance id `" + r->first + + "' changed to `" + helper.getId() + "'"); + } + def.servers.push_back(helper.getServerDefinition()); + } + return def; +} + +void +NodeHelper::getIds(multiset<string>& serverIds, multiset<string>& adapterIds, multiset<Ice::Identity>& objectIds) const +{ + assert(_instantiated); + ServerInstanceHelperDict::const_iterator p; + for(p = _serverInstances.begin(); p != _serverInstances.end(); ++p) + { + serverIds.insert(p->first); + p->second.getIds(adapterIds, objectIds); + } + for(p = _servers.begin(); p != _servers.end(); ++p) + { + serverIds.insert(p->first); + p->second.getIds(adapterIds, objectIds); + } +} + +void +NodeHelper::getReplicaGroups(set<string>& replicaGroups) const +{ + assert(_instantiated); + ServerInstanceHelperDict::const_iterator p; + for(p = _serverInstances.begin(); p != _serverInstances.end(); ++p) + { + p->second.getReplicaGroups(replicaGroups); + } + for(p = _servers.begin(); p != _servers.end(); ++p) + { + p->second.getReplicaGroups(replicaGroups); + } +} + +const NodeDescriptor& +NodeHelper::getDefinition() const +{ + return _def; +} + +const NodeDescriptor& +NodeHelper::getInstance() const +{ + assert(_instantiated); + return _instance; +} + +void +NodeHelper::getServerInfos(const string& app, const string& uuid, int revision, map<string, ServerInfo>& servers) const +{ + assert(_instantiated); + + ServerInstanceHelperDict::const_iterator p; + for(p = _serverInstances.begin(); p != _serverInstances.end(); ++p) + { + ServerInfo info; + info.node = _name; + info.application = app; + info.uuid = uuid; + info.revision = revision; + info.descriptor = p->second.getServerInstance(); + servers.insert(make_pair(p->second.getId(), info)); + } + for(p = _servers.begin(); p != _servers.end(); ++p) + { + ServerInfo info; + info.node = _name; + info.application = app; + info.uuid = uuid; + info.revision = revision; + info.descriptor = p->second.getServerInstance(); + servers.insert(make_pair(p->second.getId(), info)); + } +} + +bool +NodeHelper::hasDistributions(const string& server) const +{ + assert(_instantiated); + + // + // Get the server distributions to patch. + // + if(server.empty()) + { + ServerInstanceHelperDict::const_iterator p; + for(p = _serverInstances.begin(); p != _serverInstances.end(); ++p) + { + if(!p->second.getServerInstance()->distrib.icepatch.empty()) + { + return true; + } + } + for(p = _servers.begin(); p != _servers.end(); ++p) + { + if(!p->second.getServerInstance()->distrib.icepatch.empty()) + { + return true; + } + } + } + else + { + ServerInstanceHelperDict::const_iterator p = _serverInstances.find(server); + if(p == _serverInstances.end()) + { + p = _servers.find(server); + if(p == _servers.end()) + { + return false; + } + } + + if(!p->second.getServerInstance()->distrib.icepatch.empty()) + { + return true; + } + } + + return false; +} + +bool +NodeHelper::hasServers() const +{ + return !_serverInstances.empty() || !_servers.empty(); +} + +bool +NodeHelper::hasServer(const string& name) const +{ + return _serverInstances.find(name) != _serverInstances.end() || _servers.find(name) != _servers.end(); +} + +void +NodeHelper::print(Output& out) const +{ + assert(_instantiated); + + out << nl << "node `" << _name << "'"; + out << sb; + if(!_instance.loadFactor.empty()) + { + out << nl << "load factor = `" << _instance.loadFactor << "'"; + } + if(!_instance.description.empty()) + { + out << nl << "description = `" << _instance.description << "'"; + } + if(!_instance.variables.empty()) + { + out << nl << "variables"; + out << sb; + for(StringStringDict::const_iterator q = _instance.variables.begin(); q != _instance.variables.end(); ++q) + { + out << nl << q->first << " = `" << q->second << "'"; + } + out << eb; + } + if(!_instance.propertySets.empty()) + { + PropertySetDescriptorDict::const_iterator q; + for(q = _instance.propertySets.begin(); q != _instance.propertySets.end(); ++q) + { + out << nl << "properties `" << q->first << "'"; + out << sb; + if(!q->second.references.empty()) + { + out << nl << "references = " << toString(q->second.references); + } + PropertyDescriptorSeq::const_iterator r; + for(r = q->second.properties.begin(); r != q->second.properties.end(); ++r) + { + out << nl << r->name << " = `" << r->value << "'"; + } + out << eb; + } + } + + if(_serverInstances.empty() && _servers.empty()) + { + return; + } + + out << nl << "servers"; + out << sb; + ServerInstanceHelperDict::const_iterator p; + for(p = _serverInstances.begin(); p != _serverInstances.end(); ++p) + { + out << nl << p->first; + } + for(p = _servers.begin(); p != _servers.end(); ++p) + { + out << nl << p->first; + } + out << eb; + out << eb; +} + +void +NodeHelper::printDiff(Output& out, const NodeHelper& helper) const +{ + assert(_instantiated); + + ServerInstanceHelperDict updated1 = getDictUpdatedElts(helper._serverInstances, _serverInstances); + Ice::StringSeq removed1 = getDictRemovedElts(helper._serverInstances, _serverInstances); + ServerInstanceHelperDict updated2 = getDictUpdatedElts(helper._servers, _servers); + Ice::StringSeq removed2 = getDictRemovedElts(helper._servers, _servers); + + ServerInstanceHelperDict updated; + Ice::StringSeq removed; + updated.insert(updated1.begin(), updated1.end()); + removed.insert(removed.end(), removed1.begin(), removed1.end()); + updated.insert(updated2.begin(), updated2.end()); + removed.insert(removed.end(), removed2.begin(), removed2.end()); + + map<string, string> variables = getDictUpdatedElts(helper._def.variables, _def.variables); + Ice::StringSeq removeVariables = getDictRemovedElts(helper._def.variables, _def.variables); + + PropertySetDescriptorDict updatedPs = getDictUpdatedElts(helper._def.propertySets, _def.propertySets); + Ice::StringSeq removedPs = getDictRemovedElts(helper._def.propertySets, _def.propertySets); + + if(updated.empty() && removed.empty() && + variables.empty() && removeVariables.empty() && + updatedPs.empty() && removedPs.empty() && + _def.loadFactor == helper._def.loadFactor && + _def.description == helper._def.description) + { + return; + } + + // + // TODO: Show updated variables? + // + + out << nl << "node `" + _name + "' updated"; + out << sb; + + if(_def.loadFactor != helper._def.loadFactor) + { + out << nl << "load factor udpated"; + } + if(_def.description != helper._def.description) + { + out << nl << "description udpated"; + } + if(!updatedPs.empty() || !removedPs.empty()) + { + out << nl << "property sets udpated"; + } + if(!variables.empty() || !removeVariables.empty()) + { + out << nl << "variables udpated"; + } + if(!updated.empty() || !removed.empty()) + { + out << nl << "servers"; + out << sb; + ServerInstanceHelperDict::const_iterator p; + for(p = updated.begin(); p != updated.end(); ++p) + { + if(helper._serverInstances.find(p->first) == helper._serverInstances.end() && + helper._servers.find(p->first) == helper._servers.end()) + { + out << nl << "server `" << p->first << "' added"; + } + } + for(p = updated.begin(); p != updated.end(); ++p) + { + if(helper._serverInstances.find(p->first) != helper._serverInstances.end() || + helper._servers.find(p->first) != helper._servers.end()) + { + out << nl << "server `" << p->first << "' updated"; + } + } + for(Ice::StringSeq::const_iterator q = removed.begin(); q != removed.end(); ++q) + { + out << nl << "server `" << *q << "' removed"; + } + out << eb; + } + out << eb; +} + +ApplicationHelper::ApplicationHelper(const Ice::CommunicatorPtr& communicator, + const ApplicationDescriptor& desc, + bool enableWarning, + bool instantiate) : + _communicator(communicator), + _def(desc) +{ + if(_def.name.empty()) + { + throw DeploymentException("invalid application: empty name"); + } + + Resolver resolve(_def, communicator, enableWarning); + + if(instantiate) + { + // + // Instantiate the application definition. + // + _instance.name = _def.name; + _instance.variables = _def.variables; + _instance.serverTemplates = _def.serverTemplates; + _instance.serviceTemplates = _def.serviceTemplates; + _instance.description = resolve(_def.description, "description"); + _instance.distrib = resolve(_def.distrib); + _instance.propertySets = resolve(_def.propertySets); + + for(ReplicaGroupDescriptorSeq::iterator r = _def.replicaGroups.begin(); r != _def.replicaGroups.end(); ++r) + { + ReplicaGroupDescriptor desc; + desc.id = resolve.asId(r->id, "replica group id", false); + desc.description = resolve(r->description, "replica group description"); + desc.objects = resolve(r->objects, "replica group well-known"); + if(!r->loadBalancing) + { + resolve.exception("replica group load balancing is not set"); + } + desc.loadBalancing = LoadBalancingPolicyPtr::dynamicCast(r->loadBalancing->ice_clone()); + desc.loadBalancing->nReplicas = + resolve.asInt(r->loadBalancing->nReplicas, "replica group number of replicas"); + if(desc.loadBalancing->nReplicas.empty()) + { + resolve.exception("invalid replica group load balancing number of replicas value: empty value"); + } + else if(desc.loadBalancing->nReplicas[0] == '-') + { + resolve.exception("invalid replica group load balancing number of replicas value: inferior to 0"); + } + AdaptiveLoadBalancingPolicyPtr al = AdaptiveLoadBalancingPolicyPtr::dynamicCast(desc.loadBalancing); + if(al) + { + al->loadSample = resolve(al->loadSample, "replica group load sample"); + if(al->loadSample != "" && al->loadSample != "1" && al->loadSample != "5" && al->loadSample != "15") + { + resolve.exception("invalid load sample value (allowed values are 1, 5 or 15)"); + } + } + _instance.replicaGroups.push_back(desc); + } + + // + // Set the named property sets on the resolver. We use the + // instantiated named property sets here -- named property sets + // must be fully definied at the application level. + // + resolve.addPropertySets(_instance.propertySets); + } + + // + // Create the node helpers. + // + NodeHelperDict::const_iterator n; + for(NodeDescriptorDict::const_iterator p = _def.nodes.begin(); p != _def.nodes.end(); ++p) + { + n = _nodes.insert(make_pair(p->first, NodeHelper(p->first, p->second, resolve, instantiate))).first; + if(instantiate) + { + _instance.nodes.insert(make_pair(n->first, n->second.getInstance())); + } + } + + // + // If the application is instantiated, ensure the unicity of + // object ids, adapter ids and server ids. + // + if(instantiate) + { + multiset<string> serverIds; + multiset<string> adapterIds; + multiset<Ice::Identity> objectIds; + for(n = _nodes.begin(); n != _nodes.end(); ++n) + { + n->second.getIds(serverIds, adapterIds, objectIds); + } + + for(ReplicaGroupDescriptorSeq::iterator r = _def.replicaGroups.begin(); r != _def.replicaGroups.end(); ++r) + { + if(r->id.empty()) + { + throw DeploymentException("replica group id is empty"); + } + if(adapterIds.find(r->id) != adapterIds.end()) + { + throw DeploymentException("duplicate replica group `" + r->id + "'"); + } + adapterIds.insert(r->id); + for(ObjectDescriptorSeq::const_iterator o = r->objects.begin(); o != r->objects.end(); ++o) + { + objectIds.insert(o->id); + } + } + + for(multiset<string>::const_iterator s = serverIds.begin(); s != serverIds.end(); ++s) + { + if(serverIds.count(*s) > 1) + { + resolve.exception("duplicate server `" + *s + "'"); + } + } + for(multiset<string>::const_iterator a = adapterIds.begin(); a != adapterIds.end(); ++a) + { + if(adapterIds.count(*a) > 1) + { + resolve.exception("duplicate adapter `" + *a + "'"); + } + } + for(multiset<Ice::Identity>::const_iterator o = objectIds.begin(); o != objectIds.end(); ++o) + { + if(objectIds.count(*o) > 1) + { + resolve.exception("duplicate object `" + _communicator->identityToString(*o) + "'"); + } + } + } +} + +ApplicationUpdateDescriptor +ApplicationHelper::diff(const ApplicationHelper& helper) const +{ + ApplicationUpdateDescriptor updt; + assert(helper._def.name == _def.name); + + updt.name = _def.name; + if(_def.description != helper._def.description) + { + updt.description = new BoxedString(_def.description); + } + + updt.variables = getDictUpdatedElts(helper._def.variables, _def.variables); + updt.removeVariables = getDictRemovedElts(helper._def.variables, _def.variables); + + updt.propertySets = getDictUpdatedElts(helper._def.propertySets, _def.propertySets); + updt.removePropertySets = getDictRemovedElts(helper._def.propertySets, _def.propertySets); + + if(_def.distrib != helper._def.distrib) + { + updt.distrib = new BoxedDistributionDescriptor(_def.distrib); + } + + GetReplicaGroupId rk; + ReplicaGroupEq req; + updt.replicaGroups = getSeqUpdatedEltsWithEq(helper._def.replicaGroups, _def.replicaGroups, rk, req); + updt.removeReplicaGroups = getSeqRemovedElts(helper._def.replicaGroups, _def.replicaGroups, rk); + + TemplateDescriptorEqual eq; + updt.serverTemplates = getDictUpdatedEltsWithEq(helper._def.serverTemplates, _def.serverTemplates, eq); + updt.removeServerTemplates = getDictRemovedElts(helper._def.serverTemplates, _def.serverTemplates); + updt.serviceTemplates = getDictUpdatedEltsWithEq(helper._def.serviceTemplates, _def.serviceTemplates, eq); + updt.removeServiceTemplates = getDictRemovedElts(helper._def.serviceTemplates, _def.serviceTemplates); + + NodeHelperDict updated = getDictUpdatedElts(helper._nodes, _nodes); + for(NodeHelperDict::const_iterator p = updated.begin(); p != updated.end(); ++p) + { + NodeHelperDict::const_iterator q = helper._nodes.find(p->first); + if(q == helper._nodes.end()) + { + NodeUpdateDescriptor nodeUpdate; + const NodeDescriptor& node = p->second.getDefinition(); + nodeUpdate.name = p->first; + nodeUpdate.variables = node.variables; + nodeUpdate.servers = node.servers; + nodeUpdate.serverInstances = node.serverInstances; + nodeUpdate.loadFactor = new BoxedString(node.loadFactor); + nodeUpdate.description = new BoxedString(node.description); + updt.nodes.push_back(nodeUpdate); + } + else + { + updt.nodes.push_back(p->second.diff(q->second)); + } + } + updt.removeNodes = getDictRemovedElts(helper._nodes, _nodes); + + return updt; +} + +ApplicationDescriptor +ApplicationHelper::update(const ApplicationUpdateDescriptor& updt) const +{ + ApplicationDescriptor def; + GetReplicaGroupId rg; + + def.name = _def.name; + def.description = updt.description ? updt.description->value : _def.description; + def.distrib = updt.distrib ? updt.distrib->value : _def.distrib; + def.replicaGroups = updateSeqElts(_def.replicaGroups, updt.replicaGroups, updt.removeReplicaGroups, rg); + def.variables = updateDictElts(_def.variables, updt.variables, updt.removeVariables); + def.propertySets = updateDictElts(_def.propertySets, updt.propertySets, updt.removePropertySets); + def.serverTemplates = updateDictElts(_def.serverTemplates, updt.serverTemplates, updt.removeServerTemplates); + def.serviceTemplates = updateDictElts(_def.serviceTemplates, updt.serviceTemplates, updt.removeServiceTemplates); + + Resolver resolve(def, _communicator, false); // A resolver based on the *updated* application descriptor. + for(NodeUpdateDescriptorSeq::const_iterator p = updt.nodes.begin(); p != updt.nodes.end(); ++p) + { + NodeHelperDict::const_iterator q = _nodes.find(p->name); + if(q != _nodes.end()) // Updated node + { + NodeDescriptor desc = q->second.update(*p, resolve); + def.nodes.insert(make_pair(p->name, q->second.update(*p, resolve))); + } + else // New node + { + NodeDescriptor desc; + desc.variables = p->variables; + if(!p->removeVariables.empty()) + { + resolve.exception("can't remove variables for node `" + p->name + "': node doesn't exist"); + } + desc.propertySets = p->propertySets; + if(!p->removePropertySets.empty()) + { + resolve.exception("can't remove property sets for node `" + p->name + "': node doesn't exist"); + } + desc.servers = p->servers; + desc.serverInstances = p->serverInstances; + if(!p->removeServers.empty()) + { + resolve.exception("can't remove servers for node `" + p->name + "': node doesn't exist"); + } + desc.loadFactor = p->loadFactor ? p->loadFactor->value : string(""); + desc.description = p->description ? p->description->value : string(""); + def.nodes.insert(make_pair(p->name, desc)); + } + } + set<string> removedNodes(updt.removeNodes.begin(), updt.removeNodes.end()); + for(NodeHelperDict::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) + { + if(removedNodes.find(n->first) != removedNodes.end() || def.nodes.find(n->first) != def.nodes.end()) + { + continue; // Node was removed or updated. + } + def.nodes.insert(make_pair(n->first, n->second.getDefinition())); + } + + return def; +} + +ApplicationDescriptor +ApplicationHelper::instantiateServer(const string& node, const ServerInstanceDescriptor& instance) const +{ + // + // Copy this application descriptor definition and add a server + // instance to the given node. The caller should then construct + // an application helper with the new application definition to + // ensure it's valid. + // + ApplicationDescriptor def = _def; + NodeDescriptorDict::iterator q = def.nodes.find(node); + if(q == def.nodes.end()) + { + NodeDescriptor desc; + desc.serverInstances.push_back(instance); + def.nodes.insert(make_pair(node, desc)); + } + else + { + q->second.serverInstances.push_back(instance); + } + return def; +} + +void +ApplicationHelper::getIds(set<string>& serverIds, set<string>& adapterIds, set<Ice::Identity>& objectIds) const +{ + multiset<string> sIds; + multiset<string> aIds; + multiset<Ice::Identity> oIds; + + for(NodeHelperDict::const_iterator p = _nodes.begin(); p != _nodes.end(); ++p) + { + p->second.getIds(sIds, aIds, oIds); + } + ReplicaGroupDescriptorSeq::const_iterator r; + for(r = _def.replicaGroups.begin(); r != _def.replicaGroups.end(); ++r) + { + aIds.insert(r->id); + for(ObjectDescriptorSeq::const_iterator o = r->objects.begin(); o != r->objects.end(); ++o) + { + oIds.insert(o->id); + } + } + + copy(sIds.begin(), sIds.end(), inserter(serverIds, serverIds.begin())); + copy(aIds.begin(), aIds.end(), inserter(adapterIds, adapterIds.begin())); + copy(oIds.begin(), oIds.end(), inserter(objectIds, objectIds.begin())); +} + +void +ApplicationHelper::getReplicaGroups(set<string>& replicaGroups, set<string>& adapterReplicaGroups) const +{ + ReplicaGroupDescriptorSeq::const_iterator r; + for(r = _def.replicaGroups.begin(); r != _def.replicaGroups.end(); ++r) + { + replicaGroups.insert(r->id); + } + + set<string> allAdapterReplicaGroups; + for(NodeHelperDict::const_iterator p = _nodes.begin(); p != _nodes.end(); ++p) + { + p->second.getReplicaGroups(allAdapterReplicaGroups); + } + + // + // Only return references to replica groups which don't belong to + // this application. + // + set_difference(allAdapterReplicaGroups.begin(), allAdapterReplicaGroups.end(), + replicaGroups.begin(), replicaGroups.end(), set_inserter(adapterReplicaGroups)); +} + +const ApplicationDescriptor& +ApplicationHelper::getDefinition() const +{ + return _def; +} + +const ApplicationDescriptor& +ApplicationHelper::getInstance() const +{ + assert(!_instance.name.empty()); + return _instance; +} + +map<string, ServerInfo> +ApplicationHelper::getServerInfos(const string& uuid, int revision) const +{ + assert(!_instance.name.empty()); + + map<string, ServerInfo> servers; + for(NodeHelperDict::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) + { + n->second.getServerInfos(_def.name, uuid, revision, servers); + } + return servers; +} + +void +ApplicationHelper::getDistributions(DistributionDescriptor& distribution, + vector<string>& nodes, + const string& server) const +{ + assert(!_instance.name.empty()); + + distribution = _instance.distrib; + for(NodeHelperDict::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) + { + if(n->second.hasDistributions(server)) + { + nodes.push_back(n->first); + if(!server.empty()) + { + break; + } + } + else if(!_instance.distrib.icepatch.empty() && + ((server.empty() && n->second.hasServers()) || n->second.hasServer(server))) + { + nodes.push_back(n->first); + } + } +} + +void +ApplicationHelper::print(Output& out, const ApplicationInfo& info) const +{ + assert(!_instance.name.empty()); + + out << "application `" << _instance.name << "'"; + out << sb; + out << nl << "uuid = `" << info.uuid << "'"; + out << nl << "revision = `" << info.revision << "'"; + out << nl << "creation time = `" << IceUtil::Time::milliSeconds(info.createTime).toDateTime() << "'"; + out << nl << "created by = `" << info.createUser << "'"; + out << nl << "update time = `" << IceUtil::Time::milliSeconds(info.updateTime).toDateTime() << "'"; + out << nl << "updated by = `" << info.updateUser << "'"; + + if(!_instance.description.empty()) + { + out << nl << "description = `" << _instance.description << "'"; + } + if(!_instance.variables.empty()) + { + out << nl << "variables"; + out << sb; + for(StringStringDict::const_iterator p = _instance.variables.begin(); p != _instance.variables.end(); + ++p) + { + out << nl << p->first << " = `" << p->second << "'"; + } + out << eb; + } + if(!_instance.propertySets.empty()) + { + PropertySetDescriptorDict::const_iterator q; + for(q = _instance.propertySets.begin(); q != _instance.propertySets.end(); ++q) + { + out << nl << "properties `" << q->first << "'"; + out << sb; + if(!q->second.references.empty()) + { + out << nl << "references = " << toString(q->second.references); + } + PropertyDescriptorSeq::const_iterator r; + for(r = q->second.properties.begin(); r != q->second.properties.end(); ++r) + { + out << nl << r->name << " = `" << r->value << "'"; + } + out << eb; + } + } + if(!_instance.distrib.icepatch.empty()) + { + out << nl << "distribution"; + out << sb; + out << nl << "proxy = `" << _instance.distrib.icepatch << "'"; + if(!_instance.distrib.directories.empty()) + { + out << nl << "directories = `" << toString(_instance.distrib.directories) << "'"; + } + out << eb; + } + if(!_instance.replicaGroups.empty()) + { + out << nl << "replica groups"; + out << sb; + ReplicaGroupDescriptorSeq::const_iterator p; + for(p = _instance.replicaGroups.begin(); p != _instance.replicaGroups.end(); ++p) + { + out << nl << "id = `" << p->id << "' load balancing = `"; + if(!p->loadBalancing) + { + out << "default (return all endpoints)"; + } + else if(RandomLoadBalancingPolicyPtr::dynamicCast(p->loadBalancing)) + { + out << "random"; + } + else if(RoundRobinLoadBalancingPolicyPtr::dynamicCast(p->loadBalancing)) + { + out << "round-robin"; + } + else if(AdaptiveLoadBalancingPolicyPtr::dynamicCast(p->loadBalancing)) + { + out << "adaptive" ; + } + else + { + out << "<unknown load balancing policy>"; + } + out << "'"; + } + out << eb; + } + if(!_instance.serverTemplates.empty()) + { + out << nl << "server templates"; + out << sb; + TemplateDescriptorDict::const_iterator p; + for(p = _instance.serverTemplates.begin(); p != _instance.serverTemplates.end(); ++p) + { + out << nl << p->first; + } + out << eb; + } + if(!_instance.serviceTemplates.empty()) + { + out << nl << "service templates"; + out << sb; + TemplateDescriptorDict::const_iterator p; + for(p = _instance.serviceTemplates.begin(); p != _instance.serviceTemplates.end(); ++p) + { + out << nl << p->first; + } + out << eb; + } + if(!_nodes.empty()) + { + for(NodeHelperDict::const_iterator p = _nodes.begin(); p != _nodes.end(); ++p) + { + p->second.print(out); + } + } + out << eb; +} + +void +ApplicationHelper::printDiff(Output& out, const ApplicationHelper& helper) const +{ + assert(!_instance.name.empty()); + + out << "application `" << _def.name << "'"; + out << sb; + + { + map<string, string> variables = getDictUpdatedElts(helper._def.variables, _def.variables); + Ice::StringSeq removeVariables = getDictRemovedElts(helper._def.variables, _def.variables); + if(!variables.empty() || !removeVariables.empty()) + { + out << nl << "variables udpated"; + } + } + { + if(_def.distrib != helper._def.distrib) + { + out << nl << "distribution updated"; + } + } + { + PropertySetDescriptorDict updt = getDictUpdatedElts(helper._def.propertySets, _def.propertySets); + Ice::StringSeq removed = getDictRemovedElts(helper._def.propertySets, _def.propertySets); + if(!updt.empty() || !removed.empty()) + { + out << nl << "property sets udpated"; + } + } + { + GetReplicaGroupId rk; + ReplicaGroupEq req; + ReplicaGroupDescriptorSeq updated = + getSeqUpdatedEltsWithEq(helper._def.replicaGroups, _def.replicaGroups, rk, req); + Ice::StringSeq removed = getSeqRemovedElts(helper._def.replicaGroups, _def.replicaGroups, rk); + if(!updated.empty() || !removed.empty()) + { + out << nl << "replica groups"; + out << sb; + ReplicaGroupDescriptorSeq::iterator p = updated.begin(); + while(p != updated.end()) + { + ReplicaGroupDescriptorSeq::const_iterator r; + for(r = helper._def.replicaGroups.begin(); r != helper._def.replicaGroups.end(); + ++r) + { + if(p->id == r->id) + { + out << nl << "replica group `" << r->id << "' updated"; + p = updated.erase(p); + break; + } + } + if(r == helper._def.replicaGroups.end()) + { + ++p; + } + } + for(p = updated.begin(); p != updated.end(); ++p) + { + out << nl << "replica group `" << p->id << "' added"; + } + for(Ice::StringSeq::const_iterator q = removed.begin(); q != removed.end(); ++q) + { + out << nl << "replica group `" << *q << "' removed"; + } + out << eb; + } + } + + { + TemplateDescriptorEqual eq; + TemplateDescriptorDict updated; + updated = getDictUpdatedEltsWithEq(helper._def.serverTemplates, _def.serverTemplates, eq); + Ice::StringSeq removed = getDictRemovedElts(helper._def.serverTemplates, _def.serverTemplates); + if(!updated.empty() || !removed.empty()) + { + out << nl << "server templates"; + out << sb; + for(TemplateDescriptorDict::const_iterator p = updated.begin(); p != updated.end(); ++p) + { + if(helper._def.serverTemplates.find(p->first) == helper._def.serverTemplates.end()) + { + out << nl << "server template `" << p->first << "' added"; + } + } + for(TemplateDescriptorDict::const_iterator q = updated.begin(); q != updated.end(); ++q) + { + if(helper._def.serverTemplates.find(q->first) != helper._def.serverTemplates.end()) + { + out << nl << "server template `" << q->first << "' updated"; + } + } + for(Ice::StringSeq::const_iterator r = removed.begin(); r != removed.end(); ++r) + { + out << nl << "server template `" << *r << "' removed"; + } + out << eb; + } + } + { + TemplateDescriptorEqual eq; + TemplateDescriptorDict updated; + updated = getDictUpdatedEltsWithEq(helper._def.serviceTemplates, _def.serviceTemplates, eq); + Ice::StringSeq removed = getDictRemovedElts(helper._def.serviceTemplates, _def.serviceTemplates); + if(!updated.empty() || !removed.empty()) + { + out << nl << "service templates"; + out << sb; + for(TemplateDescriptorDict::const_iterator p = updated.begin(); p != updated.end(); ++p) + { + if(helper._def.serviceTemplates.find(p->first) == helper._def.serviceTemplates.end()) + { + out << nl << "service template `" << p->first << "' added"; + } + } + for(TemplateDescriptorDict::const_iterator q = updated.begin(); q != updated.end(); ++q) + { + if(helper._def.serviceTemplates.find(q->first) != helper._def.serviceTemplates.end()) + { + out << nl << "service template `" << q->first << "' updated"; + } + } + for(Ice::StringSeq::const_iterator r = removed.begin(); r != removed.end(); ++r) + { + out << nl << "service template `" << *r << "' removed"; + } + out << eb; + } + } + { + NodeHelperDict updated = getDictUpdatedElts(helper._nodes, _nodes); + Ice::StringSeq removed = getDictRemovedElts(helper._nodes, _nodes); + if(!updated.empty() || !removed.empty()) + { + out << nl << "nodes"; + out << sb; + for(NodeHelperDict::const_iterator p = updated.begin(); p != updated.end(); ++p) + { + NodeHelperDict::const_iterator q = helper._nodes.find(p->first); + if(q == helper._nodes.end()) + { + p->second.print(out); + } + } + for(NodeHelperDict::const_iterator r = updated.begin(); r != updated.end(); ++r) + { + NodeHelperDict::const_iterator q = helper._nodes.find(r->first); + if(q != helper._nodes.end()) + { + r->second.printDiff(out, q->second); + } + } + for(Ice::StringSeq::const_iterator s = removed.begin(); s != removed.end(); ++s) + { + out << nl << "node `" << *s << "' removed"; + } + out << eb; + } + } + out << eb; +} + +bool +IceGrid::descriptorEqual(const ServerDescriptorPtr& lhs, const ServerDescriptorPtr& rhs) +{ + IceBoxDescriptorPtr lhsIceBox = IceBoxDescriptorPtr::dynamicCast(lhs); + IceBoxDescriptorPtr rhsIceBox = IceBoxDescriptorPtr::dynamicCast(rhs); + if(lhsIceBox && rhsIceBox) + { + return IceBoxHelper(lhsIceBox) == IceBoxHelper(rhsIceBox); + } + else if(!lhsIceBox && !rhsIceBox) + { + return ServerHelper(lhs) == ServerHelper(rhs); + } + else + { + return false; + } +} + +ServerHelperPtr +IceGrid::createHelper(const ServerDescriptorPtr& desc) +{ + IceBoxDescriptorPtr iceBox = IceBoxDescriptorPtr::dynamicCast(desc); + if(iceBox) + { + return new IceBoxHelper(iceBox); + } + else + { + return new ServerHelper(desc); + } +} |