Back to index

nordugrid-arc-nox  1.1.0~rc6
Software.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <iostream>
00006 
00007 #include <arc/StringConv.h>
00008 #include <arc/client/ExecutionTarget.h>
00009 
00010 #include "Software.h"
00011 
00012 namespace Arc {
00013 
00014   Logger Software::logger(Logger::getRootLogger(), "Software");
00015   Logger SoftwareRequirement::logger(Logger::getRootLogger(), "SoftwareRequirement");
00016 
00017   const std::string Software::VERSIONTOKENS = "-.";
00018 
00019 Software::Software(const std::string& name_version) : version(""), family("") {
00020   std::size_t pos = 0;
00021 
00022   while (pos != std::string::npos) {
00023     // Look for dashes in the input string.
00024     pos = name_version.find_first_of("-", pos);
00025     if (pos != std::string::npos) {
00026       // 'name' and 'version' is defined to be seperated at the first dash which
00027       // is followed by a digit.
00028       if (isdigit(name_version[pos+1])) {
00029         name = name_version.substr(0, pos);
00030         version = name_version.substr(pos+1);
00031         tokenize(version, tokenizedVersion, VERSIONTOKENS);
00032         return;
00033       }
00034 
00035       pos++;
00036     }
00037   }
00038 
00039   // If no version part is found from the input string set the input to be the name.
00040   name = name_version;
00041 }
00042 
00043 Software::Software(const std::string& name, const std::string& version)
00044   : name(name), version(version), family("") {
00045   tokenize(version, tokenizedVersion, VERSIONTOKENS);
00046 }
00047 
00048 Software::Software(const std::string& family, const std::string& name, const std::string& version)
00049   : family(family), name(name), version(version) {
00050   tokenize(version, tokenizedVersion, VERSIONTOKENS);
00051 }
00052 
00053 std::string Software::operator()() const {
00054   if (empty()) return "";
00055   if (family.empty() && version.empty()) return name;
00056   if (family.empty()) return name + "-" + version;
00057   if (version.empty()) return family + "-" + name;
00058   return family + "-" + name + "-" + version;
00059 }
00060 
00061 bool Software::operator>(const Software& sv) const {
00062   if (family != sv.family || name != sv.name ||
00063       version.empty() || sv.version.empty() ||
00064       version == sv.version) return false;
00065 
00066   int lhsInt, rhsInt;
00067   std::list<std::string>::const_iterator lhsIt, rhsIt;
00068   for (lhsIt  = tokenizedVersion.begin(), rhsIt  = sv.tokenizedVersion.begin();
00069        lhsIt != tokenizedVersion.end() && rhsIt != sv.tokenizedVersion.end();
00070        lhsIt++, rhsIt++) {
00071     if (*lhsIt == *rhsIt)
00072       continue;
00073     if (stringto(*lhsIt, lhsInt) && stringto(*rhsIt, rhsInt)) {
00074       if (lhsInt > rhsInt) {
00075         logger.msg(VERBOSE, "%s > %s => true", (std::string)*this, (std::string)sv);
00076         return true;
00077       }
00078       if (lhsInt == rhsInt)
00079         continue;
00080     }
00081     else {
00082       logger.msg(VERBOSE, "%s > %s => false: \%s contains non numbers in the version part.", (std::string)*this, (std::string)sv, (!stringto(*lhsIt, lhsInt) ? (std::string)*this : (std::string)sv));
00083       return false;
00084     }
00085 
00086     logger.msg(VERBOSE, "%s > %s => false", (std::string)*this, (std::string)sv);
00087     return false;
00088   }
00089 
00090   if (sv.tokenizedVersion.size() != tokenizedVersion.size()) {
00091     // Left side contains extra tokens. These must only contain numbers.
00092     for (; lhsIt != tokenizedVersion.end(); lhsIt++) {
00093       if (!stringto(*lhsIt, lhsInt)) { // Try to convert ot an integer.
00094         logger.msg(VERBOSE, "%s > %s => false: %s contains non numbers in the version part.", (std::string)*this, (std::string)sv, (std::string)*this);
00095         return false;
00096       }
00097 
00098       if (lhsInt != 0) {
00099         logger.msg(VERBOSE, "%s > %s => true", (std::string)*this, (std::string)sv);
00100         return true;
00101       }
00102     }
00103   }
00104 
00105   logger.msg(VERBOSE, "%s > %s => false", (std::string)*this, (std::string)sv);
00106 
00107   return false;
00108 }
00109 
00110 std::string Software::toString(ComparisonOperator co) {
00111   if (co == &Software::operator==) return "==";
00112   if (co == &Software::operator<)  return "<";
00113   if (co == &Software::operator>)  return ">";
00114   if (co == &Software::operator<=) return "<=";
00115   if (co == &Software::operator>=) return ">=";
00116   return "!=";
00117 }
00118 
00119 Software::ComparisonOperator Software::convert(const Software::ComparisonOperatorEnum& co) {
00120   switch (co) {
00121   case Software::EQUAL:
00122     return &Software::operator==;
00123   case Software::NOTEQUAL:
00124     return &Software::operator!=;
00125   case Software::GREATERTHAN:
00126     return &Software::operator>;
00127   case Software::LESSTHAN:
00128     return &Software::operator<;
00129   case Software::GREATERTHANOREQUAL:
00130     return &Software::operator>=;
00131   case Software::LESSTHANOREQUAL:
00132     return &Software::operator<=;
00133   };
00134 }
00135 
00136 SoftwareRequirement::SoftwareRequirement(const Software& sw,
00137                                          Software::ComparisonOperatorEnum co,
00138                                          bool requiresAll)
00139   : requiresAll(requiresAll), softwareList(1, sw), comparisonOperatorList(1, Software::convert(co)),
00140     orderedSoftwareList(1, std::list<SWRelPair>(1, SWRelPair(&softwareList.front(), comparisonOperatorList.front())))
00141 {}
00142 
00143 SoftwareRequirement::SoftwareRequirement(const Software& sw,
00144                                          Software::ComparisonOperator swComOp,
00145                                          bool requiresAll)
00146   : softwareList(1, sw), comparisonOperatorList(1, swComOp), requiresAll(requiresAll),
00147     orderedSoftwareList(1, std::list<SWRelPair>(1, SWRelPair(&softwareList.front(), comparisonOperatorList.front())))
00148 {}
00149 
00150 SoftwareRequirement& SoftwareRequirement::operator=(const SoftwareRequirement& sr) {
00151   requiresAll = sr.requiresAll;
00152   softwareList = sr.softwareList;
00153   comparisonOperatorList = sr.comparisonOperatorList;
00154 
00155   orderedSoftwareList.clear();
00156   std::list<Software>::iterator itSW = softwareList.begin();
00157   std::list<Software::ComparisonOperator>::iterator itCO = comparisonOperatorList.begin();
00158   for (; itSW != softwareList.end(); itSW++, itCO++) {
00159     std::list< std::list<SWRelPair> >::iterator itRel = orderedSoftwareList.begin();
00160     for (; itRel != orderedSoftwareList.end(); itRel++) {
00161       if (itRel->front().first->getName() == itSW->getName() &&
00162           itRel->front().first->getFamily() == itSW->getFamily()) {
00163         itRel->push_back(SWRelPair(&*itSW, *itCO));
00164         break;
00165       }
00166     }
00167 
00168     if (itRel == orderedSoftwareList.end())
00169       orderedSoftwareList.push_back(std::list<SWRelPair>(1, SWRelPair(&*itSW, *itCO)));
00170   }
00171 
00172   return *this;
00173 }
00174 
00175 
00176 void SoftwareRequirement::add(const Software& sw, Software::ComparisonOperator swComOp) {
00177   if (!sw.empty()) {
00178     softwareList.push_back(sw);
00179     comparisonOperatorList.push_back(swComOp);
00180     for (std::list< std::list<SWRelPair> >::iterator it = orderedSoftwareList.begin();
00181          it != orderedSoftwareList.end(); it++) {
00182       if (it->front().first->getName() == sw.getName() &&
00183           it->front().first->getFamily() == sw.getFamily()) {
00184         it->push_back(SWRelPair(&softwareList.back(), comparisonOperatorList.back()));
00185         return;
00186       }
00187     }
00188 
00189     orderedSoftwareList.push_back(std::list<SWRelPair>(1, SWRelPair(&softwareList.back(), comparisonOperatorList.back())));
00190   }
00191 }
00192 
00193 void SoftwareRequirement::add(const Software& sw, Software::ComparisonOperatorEnum co) {
00194   add(sw, Software::convert(co));
00195 }
00196 
00197 bool SoftwareRequirement::isSatisfied(const std::list<Software>& swList) const {
00198   // Compare Software objects in the 'versions' list with those in 'swList'.
00199   std::list< std::list<SWRelPair> >::const_iterator itOSL = orderedSoftwareList.begin();
00200   for (; itOSL != orderedSoftwareList.end(); itOSL++) {
00201     // Loop over 'swList'.
00202     std::list<Software>::const_iterator itSWList = swList.begin();
00203     for (; itSWList != swList.end(); itSWList++) {
00204       std::list<SWRelPair>::const_iterator itSRL = itOSL->begin();
00205       for (; itSRL != itOSL->end(); itSRL++) {
00206         if (((*itSWList).*itSRL->second)(*itSRL->first)) { // One of the requirements satisfied.
00207           logger.msg(VERBOSE, "Requirement satisfied. %s %s %s.", (std::string)*itSWList, Software::toString(itSRL->second), (std::string)*itSRL->first);
00208           if (!requiresAll) // Only one satisfied requirement is needed.
00209             return true;
00210         }
00211         else {
00212           logger.msg(VERBOSE, "Requirement NOT satisfied. %s %s %s.", (std::string)*itSWList, Software::toString(itSRL->second), (std::string)*itSRL->first);
00213           if (requiresAll) // If requiresAll == true, then a element from the swList have to satisfy all requirements for a unique software (family + name).
00214             break;
00215         }
00216       }
00217 
00218       if (requiresAll && itSRL == itOSL->end()) // All requirements in the group have been satisfied by a single software.
00219         break;
00220     }
00221 
00222     if (requiresAll && // All requirements have to be satisfied.
00223         itSWList == swList.end()) { // End of Software list reached, ie. requirement not satisfied.
00224       logger.msg(VERBOSE, "End of list reached requirement not met.");
00225       return false;
00226     }
00227   }
00228 
00229   if (requiresAll)
00230     logger.msg(VERBOSE, "Requirements satisfied.");
00231   else
00232     logger.msg(VERBOSE, "Requirements not satisfied.");
00233 
00234   return requiresAll;
00235 }
00236 
00237 bool SoftwareRequirement::isSatisfied(const std::list<ApplicationEnvironment>& swList) const {
00238   return isSatisfied(reinterpret_cast< const std::list<Software>& >(swList));
00239 }
00240 
00241 bool SoftwareRequirement::selectSoftware(const std::list<Software>& swList) {
00242   SoftwareRequirement sr(requiresAll);
00243 
00244   std::list< std::list<SWRelPair> >::const_iterator itOSL = orderedSoftwareList.begin();
00245   for (; itOSL != orderedSoftwareList.end(); itOSL++) {
00246     Software * currentSelectedSoftware = NULL; // Pointer to the current selected software from the argument list.
00247     for (std::list<Software>::const_iterator itSWList = swList.begin();
00248          itSWList != swList.end(); itSWList++) {
00249       std::list<SWRelPair>::const_iterator itSRP = itOSL->begin();
00250       for (; itSRP != itOSL->end(); itSRP++) {
00251         if (((*itSWList).*itSRP->second)(*itSRP->first)) { // Requirement is satisfied.
00252           if (!requiresAll)
00253             break;
00254         }
00255         else if (requiresAll)
00256           break;
00257       }
00258 
00259       if (requiresAll && itSRP == itOSL->end() || // All requirements satisfied by this software.
00260           !requiresAll && itSRP != itOSL->end()) { // One requirement satisfied by this software.
00261         if (currentSelectedSoftware == NULL) { // First software to satisfy requirement. Push it to the selected software.
00262           sr.softwareList.push_back(*itSWList);
00263           sr.comparisonOperatorList.push_back(&Software::operator ==);
00264         }
00265         else if (*currentSelectedSoftware < *itSWList) { // Select the software with the highest version still satisfying the requirement.
00266           sr.softwareList.back() = *itSWList;
00267         }
00268 
00269         currentSelectedSoftware = &sr.softwareList.back();
00270       }
00271     }
00272 
00273     if (!requiresAll && sr.softwareList.size() == 1) { // Only one requirement need to be satisfied.
00274       *this = sr;
00275       return true;
00276     }
00277 
00278     if (requiresAll && currentSelectedSoftware == NULL)
00279       return false;
00280   }
00281 
00282   if (requiresAll)
00283     *this = sr;
00284 
00285   return requiresAll;
00286 }
00287 
00288 bool SoftwareRequirement::selectSoftware(const std::list<ApplicationEnvironment>& swList) {
00289   return selectSoftware(reinterpret_cast< const std::list<Software>& >(swList));
00290 }
00291 
00292 bool SoftwareRequirement::isResolved() const {
00293   if (!requiresAll)
00294     return softwareList.size() <= 1 && (softwareList.size() == 0 || comparisonOperatorList.front() == &Software::operator==);
00295   else {
00296     for (std::list< std::list<SWRelPair> >::const_iterator it = orderedSoftwareList.begin();
00297          it != orderedSoftwareList.end(); it++) {
00298       if (it->size() > 1 || it->front().second != &Software::operator==)
00299         return false;
00300     }
00301 
00302     return true;
00303   }
00304 }
00305 
00306 } // namespace Arc