Back to index

nordugrid-arc-nox  1.1.0~rc6
XRSLParser.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <list>
00008 #include <map>
00009 
00010 #include <sys/types.h>
00011 #include <sys/stat.h>
00012 #include <unistd.h>
00013 
00014 #include <arc/StringConv.h>
00015 #include <arc/URL.h>
00016 #include <arc/client/JobDescription.h>
00017 
00018 #include "RSLParser.h"
00019 #include "XRSLParser.h"
00020 
00021 namespace Arc {
00022 
00023   XRSLParser::XRSLParser()
00024     : JobDescriptionParser() {}
00025 
00026   XRSLParser::~XRSLParser() {}
00027 
00028   static Software::ComparisonOperator convertOperator(const RSLRelOp& op) {
00029     if (op == RSLNotEqual) return &Software::operator!=;
00030     if (op == RSLLess) return &Software::operator<;
00031     if (op == RSLGreater) return &Software::operator>;
00032     if (op == RSLLessOrEqual) return &Software::operator <=;
00033     if (op == RSLGreaterOrEqual) return &Software::operator>=;
00034     return &Software::operator==;
00035   }
00036 
00037   static RSLRelOp convertOperator(const Software::ComparisonOperator& op) {
00038     if (op == &Software::operator==) return RSLEqual;
00039     if (op == &Software::operator<)  return RSLLess;
00040     if (op == &Software::operator>)  return RSLGreater;
00041     if (op == &Software::operator<=) return RSLLessOrEqual;
00042     if (op == &Software::operator>=) return RSLGreaterOrEqual;
00043     return RSLNotEqual;
00044   }
00045 
00046   static std::list<const RSL*> SplitRSL(const RSL *r) {
00047     const RSLBoolean *b;
00048     std::list<const RSL*> l;
00049     if ((b = dynamic_cast<const RSLBoolean*>(r)) && b->Op() == RSLMulti)
00050       for (std::list<RSL*>::const_iterator it = b->begin();
00051            it != b->end(); it++) {
00052         std::list<const RSL*> L = SplitRSL(*it);
00053         l.insert(l.end(), L.begin(), L.end());
00054       }
00055     else
00056       l.push_back(r);
00057     return l;
00058   }
00059 
00060   bool XRSLParser::cached = true;
00061 
00062   JobDescription XRSLParser::Parse(const std::string& source) const {
00063     RSLParser parser(source);
00064     const RSL *r = parser.Parse();
00065     if (!r) {
00066       logger.msg(VERBOSE, "RSL parsing error");
00067       return JobDescription();
00068     }
00069 
00070     std::list<const RSL*> l = SplitRSL(r);
00071 
00072     std::list<JobDescription> J;
00073     for (std::list<const RSL*>::iterator it = l.begin(); it != l.end(); it++) {
00074       JobDescription j;
00075       if (!Parse(*it, j)) {
00076         logger.msg(ERROR, "XRSL parsing error");
00077         return JobDescription();
00078       }
00079 
00080       j.XRSL_elements["clientxrsl"] = source;
00081 
00082       J.push_back(j);
00083     }
00084 
00085     if (J.size() > 1) {
00086       logger.msg(WARNING, "Multiple RSL in one file not yet supported");
00087       return JobDescription();
00088     }
00089 
00090     return *J.begin();
00091   }
00092 
00093   bool XRSLParser::SingleValue(const RSLCondition *c,
00094                                std::string& value) {
00095     if (!value.empty()) {
00096       logger.msg(ERROR, "XRSL attribute %s multiply defined", c->Attr());
00097       return false;
00098     }
00099     if (c->size() != 1) {
00100       logger.msg(ERROR, "XRSL attribute %s is not a single value", c->Attr());
00101       return false;
00102     }
00103     const RSLLiteral *n = dynamic_cast<const RSLLiteral*>(*c->begin());
00104     if (!n) {
00105       logger.msg(ERROR, "XRSL attribute %s is not a string", c->Attr());
00106       return false;
00107     }
00108     value = n->Value();
00109     return true;
00110   }
00111 
00112   bool XRSLParser::ListValue(const RSLCondition *c,
00113                              std::list<std::string>& value) {
00114     if (!value.empty()) {
00115       logger.msg(ERROR, "XRSL attribute %s multiply defined", c->Attr());
00116       return false;
00117     }
00118     for (std::list<RSLValue*>::const_iterator it = c->begin();
00119          it != c->end(); it++) {
00120       const RSLLiteral *n = dynamic_cast<const RSLLiteral*>(*it);
00121       if (!n) {
00122         logger.msg(ERROR, "XRSL attribute %s is not a string", c->Attr());
00123         return false;
00124       }
00125       value.push_back(n->Value());
00126     }
00127     return true;
00128   }
00129 
00130   bool XRSLParser::SeqListValue(const RSLCondition *c,
00131                                 std::list<std::list<std::string> >& value,
00132                                 int seqlength) {
00133     if (!value.empty()) {
00134       logger.msg(ERROR, "XRSL attribute %s multiply defined", c->Attr());
00135       return false;
00136     }
00137     for (std::list<RSLValue*>::const_iterator it = c->begin();
00138          it != c->end(); it++) {
00139       const RSLSequence *s = dynamic_cast<const RSLSequence*>(*it);
00140       if (!s) {
00141         logger.msg(ERROR, "XRSL attribute %s is not sequence", c->Attr());
00142         return false;
00143       }
00144       if (seqlength != -1 && int(s->size()) != seqlength) {
00145         logger.msg(ERROR, "XRSL attribute %s has wrong sequence length",
00146                    c->Attr());
00147         return false;
00148       }
00149       std::list<std::string> l;
00150       for (std::list<RSLValue*>::const_iterator it = s->begin();
00151            it != s->end(); it++) {
00152         const RSLLiteral *n = dynamic_cast<const RSLLiteral*>(*it);
00153         if (!n) {
00154           logger.msg(ERROR, "XRSL attribute %s is not a string", c->Attr());
00155           return false;
00156         }
00157         l.push_back(n->Value());
00158       }
00159       value.push_back(l);
00160     }
00161     return true;
00162   }
00163 
00164   static char StateToShortcut(const std::string& state) {
00165     if(state == "ACCEPTED") return 'a'; // not supported
00166     if(state == "PREPARING") return 'b';
00167     if(state == "SUBMIT") return 's'; // not supported
00168     if(state == "INLRMS") return 'q';
00169     if(state == "FINISHING") return 'f';
00170     if(state == "FINISHED") return 'e';
00171     if(state == "DELETED") return 'd';
00172     if(state == "CANCELING") return 'c';
00173     return ' ';
00174   }
00175 
00176   static std::string ShortcutToState(char state) {
00177     if(state == 'a') return "ACCEPTED"; // not supported
00178     if(state == 'b') return "PREPARING";
00179     if(state == 's') return "SUBMIT"; // not supported
00180     if(state == 'q') return "INLRMS";
00181     if(state == 'f') return "FINISHING";
00182     if(state == 'e') return "FINISHED";
00183     if(state == 'd') return "DELETED";
00184     if(state == 'c') return "CANCELING";
00185     return "";
00186   }
00187 
00188   static bool AddNotificationState(
00189          NotificationType &notification,
00190          const std::string& states) {
00191     for (int n = 0; n<states.length(); n++) {
00192       std::string state = ShortcutToState(states[n]);
00193       if(state.empty()) return false;
00194       for (std::list<std::string>::iterator s = notification.States.begin();
00195                      s != notification.States.end(); s++) {
00196         if(*s == state) {
00197           state.resize(0);
00198           break;
00199         }
00200       }
00201       if(!state.empty()) notification.States.push_back(state);
00202     }
00203     return true;
00204   }
00205 
00206   static bool AddNotification(
00207          std::list<NotificationType> &notifications,
00208          const std::string& states, const std::string& email) {
00209     for(std::list<NotificationType>::iterator it =
00210                  notifications.begin(); it != notifications.end(); it++) {
00211       if(it->Email == email) {
00212         return AddNotificationState(*it,states);
00213       }
00214     }
00215     NotificationType notification;
00216     notification.Email = email;
00217     if(!AddNotificationState(notification,states)) return false;
00218     notifications.push_back(notification);
00219     return true;
00220   }
00221 
00222   bool XRSLParser::Parse(const RSL *r, JobDescription& j) const {
00223     const RSLBoolean *b;
00224     const RSLCondition *c;
00225     if ((b = dynamic_cast<const RSLBoolean*>(r))) {
00226       if (b->Op() == RSLAnd) {
00227         for (std::list<RSL*>::const_iterator it = b->begin();
00228              it != b->end(); it++)
00229           if (!Parse(*it, j)) {
00230             logger.msg(ERROR, "XRSL parsing problem");
00231             return false;
00232           }
00233       }
00234       else if (b->Op() == RSLOr) {
00235         if (b->size() != 1) {
00236           logger.msg(ERROR, "RSL conditionals currentsly not yet supported");
00237           return false;
00238         }
00239         if (!Parse(*b->begin(), j)) {
00240           logger.msg(ERROR, "XRSL parsing problem");
00241           return false;
00242         }
00243       }
00244       else {
00245         logger.msg(ERROR, "Unexpected RSL type");
00246         return false;
00247       }
00248     }
00249     else if ((c = dynamic_cast<const RSLCondition*>(r))) {
00250       if (c->Attr() == "executable")
00251         return SingleValue(c, j.Application.Executable.Name);
00252 
00253       if (c->Attr() == "arguments")
00254         return ListValue(c, j.Application.Executable.Argument);
00255 
00256       if (c->Attr() == "stdin")
00257         return SingleValue(c, j.Application.Input);
00258 
00259       if (c->Attr() == "stdout")
00260         return SingleValue(c, j.Application.Output);
00261 
00262       if (c->Attr() == "stderr")
00263         return SingleValue(c, j.Application.Error);
00264 
00265       if (c->Attr() == "inputfiles") {
00266         std::list<std::list<std::string> > ll;
00267         if (!SeqListValue(c, ll, 2))
00268           return false;
00269         for (std::list<std::list<std::string> >::iterator it = ll.begin();
00270              it != ll.end(); it++) {
00271           std::list<std::string>::iterator it2 = it->begin();
00272           FileType file;
00273           file.Name = *it2++;
00274           DataSourceType source;
00275           long fileSize;
00276           // The second string in the list (it2) might either be a URL or file size.
00277           if (!it2->empty() && !stringto(*it2, fileSize)) {
00278             source.URI = *it2;
00279             if (!source.URI)
00280               return false;
00281           }
00282           else {
00283             source.URI = file.Name;
00284           }
00285           source.Threads = -1;
00286           file.Source.push_back(source);
00287           file.KeepData = false;
00288           file.IsExecutable = false;
00289           file.DownloadToCache = true;
00290           j.DataStaging.File.push_back(file);
00291         }
00292         return true;
00293       }
00294 
00295       if (c->Attr() == "executables") {
00296         std::list<std::string> execs;
00297         if (!ListValue(c, execs))
00298           return false;
00299         for (std::list<std::string>::iterator it = execs.begin();
00300              it != execs.end(); it++)
00301           for (std::list<FileType>::iterator it2 = j.DataStaging.File.begin();
00302                it2 != j.DataStaging.File.end(); it2++)
00303             if (it2->Name == (*it))
00304               it2->IsExecutable = true;
00305         return true;
00306       }
00307 
00308       if (c->Attr() == "cache") {
00309         std::string cache;
00310         if (!SingleValue(c, cache))
00311           return false;
00312         if (lower(cache) != "yes")
00313           cached = false;
00314         return true;
00315       }
00316 
00317       if (c->Attr() == "outputfiles") {
00318         std::list<std::list<std::string> > ll;
00319         if (!SeqListValue(c, ll, 2))
00320           return false;
00321         for (std::list<std::list<std::string> >::iterator it = ll.begin();
00322              it != ll.end(); it++) {
00323           std::list<std::string>::iterator it2 = it->begin();
00324           FileType file;
00325           file.Name = *it2++;
00326           long fileSize;
00327           URL turl(*it2);
00328           // The second string in the list (it2) might be a URL or file size.
00329           if (!it2->empty() && !stringto(*it2, fileSize) && turl.Protocol() != "file") {
00330             if (!turl)
00331               return false;
00332             DataTargetType target;
00333             target.URI = turl;
00334             target.Threads = -1;
00335             file.Target.push_back(target);
00336           } else
00337             file.KeepData = true;
00338           file.IsExecutable = false;
00339           file.DownloadToCache = false;
00340           j.DataStaging.File.push_back(file);
00341         }
00342         return true;
00343       }
00344 
00345       if (c->Attr() == "queue") {
00346         std::string queueName;
00347         if (!SingleValue(c, queueName))
00348           return false;
00349         if (j.Resources.CandidateTarget.empty()) {
00350           ResourceTargetType candidateTarget;
00351           candidateTarget.EndPointURL = URL();
00352           candidateTarget.QueueName = queueName;
00353           j.Resources.CandidateTarget.push_back(candidateTarget);
00354         }
00355         else
00356           j.Resources.CandidateTarget.front().QueueName = queueName;
00357         return true;
00358       }
00359 
00360       if (c->Attr() == "starttime") {
00361         std::string time;
00362         if (!SingleValue(c, time))
00363           return false;
00364         j.Application.ProcessingStartTime = time;
00365         return true;
00366       }
00367 
00368       if (c->Attr() == "lifetime") {
00369         std::string time;
00370         if (!SingleValue(c, time))
00371           return false;
00372         if(GetHint("SOURCEDIALECT") == "GRIDMANAGER") {
00373           j.Resources.SessionLifeTime = Period(time, PeriodSeconds);
00374         } else {
00375           j.Resources.SessionLifeTime = Period(time, PeriodDays);
00376         }
00377         return true;
00378       }
00379 
00380       if (c->Attr() == "cputime") {
00381         std::string time;
00382         if (!SingleValue(c, time))
00383           return false;
00384         if(GetHint("SOURCEDIALECT") == "GRIDMANAGER") {
00385           j.Resources.TotalCPUTime = Period(time, PeriodSeconds).GetPeriod();
00386         } else {
00387           j.Resources.TotalCPUTime = Period(time, PeriodMinutes).GetPeriod();
00388         }
00389         return true;
00390       }
00391 
00392       if (c->Attr() == "walltime") {
00393         std::string time;
00394         if (!SingleValue(c, time))
00395           return false;
00396         if(GetHint("SOURCEDIALECT") == "GRIDMANAGER") {
00397           j.Resources.TotalWallTime = Period(time, PeriodSeconds).GetPeriod();
00398         } else {
00399           j.Resources.TotalWallTime = Period(time, PeriodMinutes).GetPeriod();
00400         }
00401         return true;
00402       }
00403 
00404       if (c->Attr() == "gridtime") {
00405         std::string time;
00406         if (!SingleValue(c, time))
00407           return false;
00408         if(GetHint("SOURCEDIALECT") == "GRIDMANAGER") {
00409           j.Resources.TotalCPUTime.range = Period(time, PeriodSeconds).GetPeriod();
00410         } else {
00411           j.Resources.TotalCPUTime.range = Period(time, PeriodMinutes).GetPeriod();
00412         }
00413         j.Resources.TotalCPUTime.benchmark = std::pair<std::string, double>("ARC-clockrate", 2800);
00414         return true;
00415       }
00416 
00417       if (c->Attr() == "benchmarks") {
00418         std::list<std::list<std::string> > bm;
00419         if (!SeqListValue(c, bm, 3))
00420           return false;
00421         double bValue;
00422         // Only the first parsable benchmark is currently supported.
00423         for (std::list< std::list<std::string> >::const_iterator it = bm.begin();
00424              it != bm.end(); it++) {
00425           std::list<std::string>::const_iterator itB = it->begin();
00426           if (!stringto(*++itB, bValue))
00427             continue;
00428           if(GetHint("SOURCEDIALECT") == "GRIDMANAGER") {
00429             j.Resources.TotalCPUTime.range = Period(*++itB, PeriodSeconds).GetPeriod();
00430           } else {
00431             j.Resources.TotalCPUTime.range = Period(*++itB, PeriodMinutes).GetPeriod();
00432           }
00433           j.Resources.TotalCPUTime.benchmark = std::pair<std::string, double>(it->front(), bValue);
00434           return true;
00435         }
00436         return false;
00437       }
00438 
00439       if (c->Attr() == "memory") {
00440         std::string mem;
00441         if (!SingleValue(c, mem))
00442           return false;
00443         j.Resources.IndividualPhysicalMemory = stringto<int64_t>(mem);
00444         return true;
00445       }
00446 
00447       if (c->Attr() == "disk") {
00448         std::string disk;
00449         if (!SingleValue(c, disk))
00450           return false;
00451           j.Resources.DiskSpaceRequirement.DiskSpace = stringto<int64_t>(disk);
00452         return true;
00453       }
00454 
00455       if (c->Attr() == "runtimeenvironment") {
00456         std::string runtime;
00457         if (!SingleValue(c, runtime))
00458           return false;
00459         j.Resources.RunTimeEnvironment.add(Software(runtime), convertOperator(c->Op()));
00460         return true;
00461        }
00462 
00463       if (c->Attr() == "middleware") {
00464         std::string cetype;
00465         if (!SingleValue(c, cetype))
00466           return false;
00467         j.Resources.CEType.add(Software(cetype), convertOperator(c->Op()));
00468         return true;
00469       }
00470 
00471       if (c->Attr() == "opsys") {
00472         std::string opsys;
00473         if (!SingleValue(c, opsys))
00474           return false;
00475         j.Resources.OperatingSystem.add(Software(opsys), convertOperator(c->Op()));
00476         return true;
00477       }
00478 
00479       if (c->Attr() == "join") {
00480         std::string join;
00481         if (!SingleValue(c, join))
00482           return false;
00483         j.Application.Join = (lower(join) == "true");
00484         return true;
00485       }
00486 
00487       if (c->Attr() == "gmlog")
00488         return SingleValue(c, j.Application.LogDir);
00489 
00490       if (c->Attr() == "jobname")
00491         return SingleValue(c, j.Identification.JobName);
00492 
00493       if (c->Attr() == "ftpthreads") {
00494         std::string sthreads;
00495         if (!SingleValue(c, sthreads))
00496           return false;
00497         int threads = stringtoi(sthreads);
00498         for (std::list<FileType>::iterator it = j.DataStaging.File.begin();
00499              it != j.DataStaging.File.end(); it++) {
00500           if (it->Source.front().Threads > threads || it->Source.front().Threads == -1)
00501             it->Source.front().Threads = threads;
00502           if (it->Target.front().Threads > threads || it->Target.front().Threads == -1)
00503             it->Target.front().Threads = threads;
00504         }
00505         return true;
00506       }
00507 
00508       if (c->Attr() == "acl") {
00509         std::string acl;
00510         if (!SingleValue(c, acl))
00511           return false;
00512         XMLNode node(acl);
00513         node.New(j.Application.AccessControl);
00514         return true;
00515       }
00516 
00517       if (c->Attr() == "cluster") {
00518         std::string cluster;
00519         if (!SingleValue(c, cluster))
00520           return false;
00521         if (!URL(cluster))
00522           return false;
00523         if (j.Resources.CandidateTarget.empty()) {
00524           ResourceTargetType candidateTarget;
00525           candidateTarget.EndPointURL = cluster;
00526           candidateTarget.QueueName = "";
00527           j.Resources.CandidateTarget.push_back(candidateTarget);
00528         }
00529         else
00530           j.Resources.CandidateTarget.front().EndPointURL = cluster;
00531         return true;
00532       }
00533 
00534       if (c->Attr() == "notify") {
00535         std::list<std::string> l;
00536         if (!ListValue(c, l))
00537           return false;
00538         if (l.size() < 1) {
00539           logger.msg(VERBOSE, "Syntax error in notify attribute. At least one notification description must be specified.");
00540           return false;
00541         }
00542         for (std::list<std::string>::iterator notf = l.begin();
00543                                  notf != l.end(); ++notf) {
00544           std::list<std::string> ll;
00545           tokenize(*notf, ll, " \t");
00546           if (ll.size() < 2) {
00547             logger.msg(VERBOSE, "Syntax error in notify attribute. One or more job states and one or more email addresses must be specified.");
00548             return false;
00549           }
00550           if (ll.front().find('@') != std::string::npos) {
00551             logger.msg(VERBOSE, "Syntax error in notify attribute. Item cannot begin with an email address.");
00552             return false;
00553           }
00554           std::list<std::string>::iterator it = ll.begin();
00555           std::string states = *it;
00556           for (it++; it != ll.end(); it++) {
00557             if (it->find('@') == std::string::npos) {
00558               logger.msg(VERBOSE, "Syntax error in notify attribute. Item must contain only an email addresses after state flags.");
00559               return false;
00560             }
00561             if(!AddNotification(j.Application.Notification,states,*it)) {
00562               logger.msg(VERBOSE, "Syntax error in notify attribute. Item contains wrong state flags.");
00563               return false;
00564             }
00565           }
00566         }
00567         return true;
00568       }
00569 
00570       if (c->Attr() == "replicacollection") {
00571         std::string collection;
00572         if (!SingleValue(c, collection))
00573           return false;
00574         URL url(collection);
00575         if (!url)
00576           return false;
00577         for (std::list<FileType>::iterator it = j.DataStaging.File.begin();
00578              it != j.DataStaging.File.end(); it++)
00579           it->DataIndexingService.push_back(url);
00580         return true;
00581       }
00582 
00583       if (c->Attr() == "rerun") {
00584         std::string rerun;
00585         if (!SingleValue(c, rerun))
00586           return false;
00587         j.Application.Rerun = stringtoi(rerun);
00588         return true;
00589       }
00590 
00591       if (c->Attr() == "architecture")
00592         return SingleValue(c, j.Resources.Platform);
00593 
00594       if (c->Attr() == "nodeaccess") {
00595         std::list<std::string> l;
00596         if (!ListValue(c, l))
00597           return false;
00598         for (std::list<std::string>::iterator it = l.begin();
00599              it != l.end(); it++)
00600           if (*it == "inbound")
00601             j.Resources.NodeAccess = (j.Resources.NodeAccess == NAT_OUTBOUND || j.Resources.NodeAccess == NAT_INOUTBOUND ? NAT_INOUTBOUND : NAT_INBOUND);
00602           else if (*it == "outbound")
00603             j.Resources.NodeAccess = (j.Resources.NodeAccess == NAT_INBOUND || j.Resources.NodeAccess == NAT_INOUTBOUND ? NAT_INOUTBOUND : NAT_OUTBOUND);
00604           else {
00605             logger.msg(VERBOSE, "Invalid nodeaccess value: %s", *it);
00606             return false;
00607           }
00608         return true;
00609       }
00610 
00611       if (c->Attr() == "dryrun") {
00612         std::string dryrun;
00613         if (!SingleValue(c, dryrun))
00614           return false;
00615         if (lower(dryrun) == "yes" || lower(dryrun) == "dryrun")
00616          j.XRSL_elements["dryrun"] = "yes";
00617         return true;
00618       }
00619 
00620       // Underscore, in 'rsl_substitution', is removed by normalization.
00621       if (c->Attr() == "rslsubstitution")
00622         // Handled internally by the RSL parser
00623         return true;
00624 
00625       if (c->Attr() == "environment") {
00626         std::list<std::list<std::string> > ll;
00627         if (!SeqListValue(c, ll, 2))
00628           return false;
00629         for (std::list<std::list<std::string> >::iterator it = ll.begin();
00630              it != ll.end(); it++) {
00631           j.Application.Environment.push_back(std::make_pair(it->front(), it->back()));
00632         }
00633         return true;
00634       }
00635 
00636       if (c->Attr() == "count") {
00637         std::string count;
00638         if (!SingleValue(c, count))
00639           return false;
00640         j.Resources.SlotRequirement.ProcessPerHost = stringtoi(count);
00641         return true;
00642       }
00643 
00644       if (c->Attr() == "jobreport") {
00645         std::string jobreport;
00646         if (!SingleValue(c, jobreport))
00647           return false;
00648         if (!URL(jobreport))
00649           return false;
00650         j.Application.RemoteLogging.push_back(URL(jobreport));
00651         return true;
00652       }
00653 
00654       if (c->Attr() == "credentialserver") {
00655         std::string credentialserver;
00656         if (!SingleValue(c, credentialserver))
00657           return false;
00658         if (!URL(credentialserver))
00659           return false;
00660         j.Application.CredentialService.push_back(credentialserver);
00661         return true;
00662       }
00663 
00664       // GM-side attributes.
00665       if (c->Attr() == "action") {
00666         std::string action;
00667         if (!SingleValue(c, action))
00668           return false;
00669         if (action != "request" && action != "cancel" && action != "clean") {
00670           logger.msg(VERBOSE, "Invalid action value %s", action);
00671           return false;
00672         }
00673         j.XRSL_elements["action"] = action;
00674         return true;
00675       }
00676 
00677       if (c->Attr() == "hostname") {
00678         std::string hostname;
00679         if (!SingleValue(c, hostname))
00680           return false;
00681         j.XRSL_elements["hostname"] = hostname;
00682         return true;
00683       }
00684 
00685       if (c->Attr() == "jobid") {
00686         std::string jobid;
00687         if (!SingleValue(c, jobid))
00688           return false;
00689         j.XRSL_elements["jobid"] = jobid;
00690         return true;
00691       }
00692 
00693       if (c->Attr() == "clientxrsl") {
00694         std::string clientxrsl;
00695         if (!SingleValue(c, clientxrsl))
00696           return false;
00697         j.XRSL_elements["clientxrsl"] = clientxrsl;
00698         return true;
00699       }
00700 
00701       if (c->Attr() == "clientsoftware") {
00702         std::string clientsoftware;
00703         if (!SingleValue(c, clientsoftware))
00704           return false;
00705         j.XRSL_elements["clientsoftware"] = clientsoftware;
00706         return true;
00707       }
00708 
00709       if (c->Attr() == "savestate") {
00710         std::string savestate;
00711         if (!SingleValue(c, savestate))
00712           return false;
00713         j.XRSL_elements["savestate"] = savestate;
00714         return true;
00715       }
00716 
00717       // Unsupported Globus RSL attributes.
00718       if (c->Attr() == "resourcemanagercontact" ||
00719           c->Attr() == "directory" ||
00720           c->Attr() == "maxcputime" ||
00721           c->Attr() == "maxwalltime" ||
00722           c->Attr() == "maxtime" ||
00723           c->Attr() == "maxmemory" ||
00724           c->Attr() == "minmemory" ||
00725           c->Attr() == "grammyjob" ||
00726           c->Attr() == "project" ||
00727           c->Attr() == "hostcount" ||
00728           c->Attr() == "label" ||
00729           c->Attr() == "subjobcommstype" ||
00730           c->Attr() == "subjobstarttype" ||
00731           c->Attr() == "filecleanup" ||
00732           c->Attr() == "filestagein" ||
00733           c->Attr() == "filestageinshared" ||
00734           c->Attr() == "filestageout" ||
00735           c->Attr() == "gasscache" ||
00736           c->Attr() == "jobtype" ||
00737           c->Attr() == "librarypath" ||
00738           c->Attr() == "remoteiourl" ||
00739           c->Attr() == "scratchdir") {
00740         logger.msg(WARNING, "The specified Globus attribute (%s) is not supported. %s ignored.", c->Attr(), c->Attr());
00741         return true;
00742       }
00743 
00744       logger.msg(VERBOSE, "Unknown XRSL attribute: %s - Ignoring it.", c->Attr());
00745       return true;
00746     }
00747     else {
00748       logger.msg(ERROR, "Unexpected RSL type");
00749       return false;
00750     }
00751 
00752     // This part will run only when the parsing is at the end of the xrsl file
00753 
00754     // Value defined in "cache" element is applicable to all input files
00755     for (std::list<FileType>::iterator it = j.DataStaging.File.begin();
00756          it != j.DataStaging.File.end(); it++)
00757       if (!it->Source.empty())
00758         it->DownloadToCache = cached;
00759 
00760     // Since OR expressions in XRSL is spilt into serveral JobDescriptions the requirement for RTE must be all (AND).
00761     j.Resources.RunTimeEnvironment.setRequirement(true);
00762 
00763     return true;
00764   }
00765 
00766   std::string XRSLParser::UnParse(const JobDescription& j) const {
00767     RSLBoolean r(RSLAnd);
00768 
00769     if (!j.Application.Executable.Name.empty()) {
00770       RSLList *l = new RSLList;
00771       l->Add(new RSLLiteral(j.Application.Executable.Name));
00772       r.Add(new RSLCondition("executable", RSLEqual, l));
00773     }
00774 
00775     if (!j.Application.Executable.Argument.empty()) {
00776       RSLList *l = new RSLList;
00777       for (std::list<std::string>::const_iterator it = j.Application.Executable.Argument.begin();
00778            it != j.Application.Executable.Argument.end(); it++)
00779         l->Add(new RSLLiteral(*it));
00780       r.Add(new RSLCondition("arguments", RSLEqual, l));
00781     }
00782 
00783     if (!j.Application.Input.empty()) {
00784       RSLList *l = new RSLList;
00785       l->Add(new RSLLiteral(j.Application.Input));
00786       r.Add(new RSLCondition("stdin", RSLEqual, l));
00787     }
00788 
00789     if (j.Application.Join) {
00790       if (!j.Application.Output.empty() && !j.Application.Error.empty() && j.Application.Output != j.Application.Error) {
00791         logger.msg(ERROR, "Incompatible RSL attributes");
00792         return "";
00793       }
00794       if (!j.Application.Output.empty() || j.Application.Error.empty()) {
00795         const std::string& eo = !j.Application.Output.empty() ? j.Application.Output : j.Application.Error;
00796         RSLList *l1 = new RSLList;
00797         l1->Add(new RSLLiteral(eo));
00798         r.Add(new RSLCondition("stdout", RSLEqual, l1));
00799         RSLList *l2 = new RSLList;
00800         l2->Add(new RSLLiteral(eo));
00801         r.Add(new RSLCondition("stderr", RSLEqual, l2));
00802       }
00803     }
00804     else {
00805       if (!j.Application.Output.empty()) {
00806         RSLList *l = new RSLList;
00807         l->Add(new RSLLiteral(j.Application.Output));
00808         r.Add(new RSLCondition("stdout", RSLEqual, l));
00809       }
00810 
00811       if (!j.Application.Error.empty()) {
00812         RSLList *l = new RSLList;
00813         l->Add(new RSLLiteral(j.Application.Error));
00814         r.Add(new RSLCondition("stderr", RSLEqual, l));
00815       }
00816     }
00817 
00818     if (j.Resources.TotalCPUTime.range > -1) {
00819       RSLList *l = new RSLList;
00820       if(GetHint("TARGETDIALECT") == "GRIDMANAGER") {
00821         // Seconds
00822         l->Add(new RSLLiteral(tostring(j.Resources.TotalCPUTime.range)));
00823       } else {
00824         // Free format
00825         l->Add(new RSLLiteral((std::string)Period(j.Resources.TotalCPUTime.range)));
00826       }
00827       r.Add(new RSLCondition("cputime", RSLEqual, l));
00828     }
00829 
00830     if (j.Resources.TotalWallTime.range > -1) {
00831       RSLList *l = new RSLList;
00832       if(GetHint("TARGETDIALECT") == "GRIDMANAGER") {
00833         // Seconds
00834         l->Add(new RSLLiteral(tostring(j.Resources.TotalWallTime.range)));
00835       } else {
00836         // Free format
00837         l->Add(new RSLLiteral((std::string)Period(j.Resources.TotalWallTime.range)));
00838       }
00839       r.Add(new RSLCondition("walltime", RSLEqual, l));
00840     }
00841 
00842     if (j.Resources.IndividualPhysicalMemory > -1) {
00843       RSLList *l = new RSLList;
00844       l->Add(new RSLLiteral(tostring(j.Resources.IndividualPhysicalMemory)));
00845       r.Add(new RSLCondition("memory", RSLEqual, l));
00846     }
00847 
00848     if (!j.Application.Environment.empty()) {
00849       RSLList *l = new RSLList;
00850       for (std::list< std::pair<std::string, std::string> >::const_iterator it = j.Application.Environment.begin();
00851            it != j.Application.Environment.end(); it++) {
00852         RSLList *s = new RSLList;
00853         s->Add(new RSLLiteral(it->first));
00854         s->Add(new RSLLiteral(it->second));
00855         l->Add(new RSLSequence(s));
00856       }
00857       r.Add(new RSLCondition("environment", RSLEqual, l));
00858     }
00859 
00860     if (!j.DataStaging.File.empty() || !j.Application.Executable.Name.empty() || !j.Application.Input.empty()) {
00861       struct stat fileStat;
00862       RSLList *l = NULL;
00863       for (std::list<FileType>::const_iterator it = j.DataStaging.File.begin();
00864            it != j.DataStaging.File.end(); it++) {
00865         if (it->Source.empty())
00866           continue;
00867         RSLList *s = new RSLList;
00868         s->Add(new RSLLiteral(it->Name));
00869         if (it->Source.front().URI.Protocol() == "file") {
00870           if (stat(it->Source.front().URI.Path().c_str(), &fileStat) == 0)
00871             s->Add(new RSLLiteral(tostring(fileStat.st_size)));
00872           else {
00873             logger.msg(ERROR, "Can not stat local input file %s", it->Source.front().URI.Path());
00874             delete s;
00875             if (l)
00876               delete l;
00877             return "";
00878           }
00879         }
00880         else
00881           s->Add(new RSLLiteral(it->Source.front().URI.fullstr()));
00882         if (!l)
00883           l = new RSLList;
00884         l->Add(new RSLSequence(s));
00885       }
00886 
00887       if (l)
00888         r.Add(new RSLCondition("inputfiles", RSLEqual, l));
00889 
00890       // Executables
00891       l = NULL;
00892       for (std::list<FileType>::const_iterator it = j.DataStaging.File.begin();
00893            it != j.DataStaging.File.end(); it++)
00894         if (it->IsExecutable) {
00895           if (!l)
00896             l = new RSLList;
00897           l->Add(new RSLLiteral(it->Name));
00898         }
00899       if (l)
00900         r.Add(new RSLCondition("executables", RSLEqual, l));
00901     }
00902 
00903     if (!j.DataStaging.File.empty() || !j.Application.Output.empty() || !j.Application.Error.empty()) {
00904       RSLList *l = NULL;
00905       for (std::list<FileType>::const_iterator it = j.DataStaging.File.begin();
00906            it != j.DataStaging.File.end(); it++) {
00907         if (!it->Target.empty()) {
00908           RSLList *s = new RSLList;
00909           s->Add(new RSLLiteral(it->Name));
00910           if (!it->Target.front().URI || it->Target.front().URI.Protocol() == "file")
00911             s->Add(new RSLLiteral(""));
00912           else {
00913             URL url(it->Target.front().URI);
00914             if (it->DownloadToCache)
00915               url.AddOption("cache", "yes");
00916             s->Add(new RSLLiteral(url.fullstr()));
00917           }
00918           if (!l)
00919             l = new RSLList;
00920           l->Add(new RSLSequence(s));
00921         }
00922         else if (it->KeepData) {
00923           RSLList *s = new RSLList;
00924           s->Add(new RSLLiteral(it->Name));
00925           s->Add(new RSLLiteral(""));
00926           if (!l)
00927             l = new RSLList;
00928           l->Add(new RSLSequence(s));
00929         }
00930       }
00931 
00932       if (l)
00933         r.Add(new RSLCondition("outputfiles", RSLEqual, l));
00934     }
00935 
00936     if (!j.Resources.CandidateTarget.empty()) {
00937       RSLList *l = new RSLList;
00938       l->Add(new RSLLiteral(j.Resources.CandidateTarget.front().QueueName));
00939       r.Add(new RSLCondition("queue", RSLEqual, l));
00940     }
00941 
00942     if (j.Application.Rerun != -1) {
00943       RSLList *l = new RSLList;
00944       l->Add(new RSLLiteral(tostring(j.Application.Rerun)));
00945       r.Add(new RSLCondition("rerun", RSLEqual, l));
00946     }
00947 
00948     if (j.Resources.SessionLifeTime != -1) {
00949       RSLList *l = new RSLList;
00950       if(GetHint("TARGETDIALECT") == "GRIDMANAGER") {
00951         // Seconds
00952         l->Add(new RSLLiteral(tostring(j.Resources.SessionLifeTime.GetPeriod())));
00953       } else {
00954         // Free format
00955         l->Add(new RSLLiteral((std::string)j.Resources.SessionLifeTime));
00956       }
00957       r.Add(new RSLCondition("lifetime", RSLEqual, l));
00958     }
00959 
00960     if (j.Resources.DiskSpaceRequirement.DiskSpace > -1) {
00961       RSLList *l = new RSLList;
00962       l->Add(new RSLLiteral(tostring(j.Resources.DiskSpaceRequirement.DiskSpace)));
00963       r.Add(new RSLCondition("disk", RSLEqual, l));
00964     }
00965 
00966     if (!j.Resources.RunTimeEnvironment.empty()) {
00967       std::list<Software>::const_iterator itSW = j.Resources.RunTimeEnvironment.getSoftwareList().begin();
00968       std::list<Software::ComparisonOperator>::const_iterator itCO = j.Resources.RunTimeEnvironment.getComparisonOperatorList().begin();
00969       for (; itSW != j.Resources.RunTimeEnvironment.getSoftwareList().end(); itSW++, itCO++) {
00970         RSLList *l = new RSLList;
00971         l->Add(new RSLLiteral(*itSW));
00972         r.Add(new RSLCondition("runtimeenvironment", convertOperator(*itCO), l));
00973       }
00974     }
00975 
00976     if (!j.Resources.CEType.empty()) {
00977       std::list<Software>::const_iterator itSW = j.Resources.CEType.getSoftwareList().begin();
00978       std::list<Software::ComparisonOperator>::const_iterator itCO = j.Resources.CEType.getComparisonOperatorList().begin();
00979       for (; itSW != j.Resources.CEType.getSoftwareList().end(); itSW++, itCO++) {
00980         RSLList *l = new RSLList;
00981         l->Add(new RSLLiteral(*itSW));
00982         r.Add(new RSLCondition("middleware", convertOperator(*itCO), l));
00983       }
00984     }
00985 
00986     if (!j.Resources.OperatingSystem.empty()) {
00987       std::list<Software>::const_iterator itSW = j.Resources.OperatingSystem.getSoftwareList().begin();
00988       std::list<Software::ComparisonOperator>::const_iterator itCO = j.Resources.OperatingSystem.getComparisonOperatorList().begin();
00989       for (; itSW != j.Resources.OperatingSystem.getSoftwareList().end(); itSW++, itCO++) {
00990         RSLList *l = new RSLList;
00991         l->Add(new RSLLiteral((std::string)*itSW));
00992         r.Add(new RSLCondition("opsys", convertOperator(*itCO), l));
00993       }
00994     }
00995 
00996     if (!j.Resources.Platform.empty()) {
00997       RSLList *l = new RSLList;
00998       l->Add(new RSLLiteral(j.Resources.Platform));
00999       r.Add(new RSLCondition("architecture", RSLEqual, l));
01000     }
01001 
01002     if (j.Resources.SlotRequirement.ProcessPerHost > -1) {
01003       RSLList *l = new RSLList;
01004       l->Add(new RSLLiteral(tostring(j.Resources.SlotRequirement.ProcessPerHost)));
01005       r.Add(new RSLCondition("count", RSLEqual, l));
01006     }
01007 
01008     if (j.Application.ProcessingStartTime != -1) {
01009       RSLList *l = new RSLList;
01010       l->Add(new RSLLiteral(j.Application.ProcessingStartTime.str(MDSTime)));
01011       r.Add(new RSLCondition("starttime", RSLEqual, l));
01012     }
01013 
01014     if (!j.Application.LogDir.empty()) {
01015       RSLList *l = new RSLList;
01016       l->Add(new RSLLiteral(j.Application.LogDir));
01017       r.Add(new RSLCondition("gmlog", RSLEqual, l));
01018     }
01019 
01020     if (!j.Identification.JobName.empty()) {
01021       RSLList *l = new RSLList;
01022       l->Add(new RSLLiteral(j.Identification.JobName));
01023       r.Add(new RSLCondition("jobname", RSLEqual, l));
01024     }
01025 
01026     if (j.Application.AccessControl) {
01027       RSLList *l = new RSLList;
01028       std::string acl;
01029       j.Application.AccessControl.GetXML(acl, true);
01030       l->Add(new RSLLiteral(acl));
01031       r.Add(new RSLCondition("acl", RSLEqual, l));
01032     }
01033 
01034     if (!j.Application.Notification.empty()) {
01035       RSLList *l = new RSLList;
01036       for (std::list<NotificationType>::const_iterator it = j.Application.Notification.begin();
01037            it != j.Application.Notification.end(); it++) {
01038         // Suboptimal, group emails later
01039         std::string states;
01040         for (std::list<std::string>::const_iterator s = it->States.begin();
01041              s != it->States.end(); s++) {
01042           char state = StateToShortcut(*s);
01043           if (state != ' ') states+=state;
01044         }
01045         l->Add(new RSLLiteral(states + " " + it->Email));
01046       }
01047       r.Add(new RSLCondition("notify", RSLEqual, l));
01048     }
01049 
01050     if (!j.Application.RemoteLogging.empty()) {
01051       RSLList *l = new RSLList;
01052       l->Add(new RSLLiteral(j.Application.RemoteLogging.front().fullstr()));
01053       r.Add(new RSLCondition("jobreport", RSLEqual, l));
01054     }
01055 
01056     if (!j.Application.CredentialService.empty()) {
01057       RSLList *l = new RSLList;
01058       l->Add(new RSLLiteral(j.Application.CredentialService.front().fullstr()));
01059       r.Add(new RSLCondition("credentialserver", RSLEqual, l));
01060     }
01061 
01062     for (std::map<std::string, std::string>::const_iterator it = j.XRSL_elements.begin();
01063          it != j.XRSL_elements.end(); it++) {
01064       RSLList *l = new RSLList;
01065       l->Add(new RSLLiteral(it->second));
01066       r.Add(new RSLCondition(it->first, RSLEqual, l));
01067     }
01068 
01069     std::stringstream ss;
01070     ss << r;
01071     return ss.str();
01072   }
01073 
01074 } // namespace Arc