Back to index

nordugrid-arc-nox  1.1.0~rc6
JDLParser.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 <glibmm.h>
00008 
00009 #include <arc/StringConv.h>
00010 #include <arc/XMLNode.h>
00011 #include <arc/URL.h>
00012 #include <arc/Logger.h>
00013 
00014 #include "JDLParser.h"
00015 
00016 #define ADDJDLSTRING(X, Y) (!(X).empty() ? "  " Y " = \"" + X + "\";\n" : "")
00017 #define ADDJDLNUMBER(X, Y) ((X) > -1 ? "  " Y " = \"" + tostring(X) + "\";\n" : "")
00018 
00019 namespace Arc {
00020 
00021   JDLParser::JDLParser()
00022     : JobDescriptionParser() {}
00023 
00024   JDLParser::~JDLParser() {}
00025 
00026   bool JDLParser::splitJDL(const std::string& original_string,
00027                            std::list<std::string>& lines) const {
00028     // Clear the return variable
00029     lines.clear();
00030 
00031     std::string jdl_text = original_string;
00032 
00033     bool quotation = false;
00034     std::list<char> stack;
00035     std::string actual_line;
00036 
00037     for (int i = 0; i < jdl_text.size() - 1; i++) {
00038       // Looking for control character marks the line end
00039       if (jdl_text[i] == ';' && !quotation && stack.empty()) {
00040         lines.push_back(actual_line);
00041         actual_line.clear();
00042         continue;
00043       }
00044       else if (jdl_text[i] == ';' && !quotation && stack.back() == '{') {
00045         logger.msg(ERROR, "[JDLParser] Semicolon (;) is not allowed inside brackets, at '%s;'.", actual_line);
00046         return false;
00047       }
00048       // Determinize the quotations
00049       if (jdl_text[i] == '"') {
00050         if (!quotation)
00051           quotation = true;
00052         else if (jdl_text[i - 1] != '\\')
00053           quotation = false;
00054       }
00055       else if (!quotation) {
00056         if (jdl_text[i] == '{' || jdl_text[i] == '[')
00057           stack.push_back(jdl_text[i]);
00058         else if (jdl_text[i] == '}') {
00059           if (stack.back() == '{')
00060             stack.pop_back();
00061           else
00062             return false;
00063         }
00064         else if (jdl_text[i] == ']') {
00065           if (stack.back() == '[')
00066             stack.pop_back();
00067           else
00068             return false;
00069         }
00070       }
00071       actual_line += jdl_text[i];
00072     }
00073     return true;
00074   }
00075 
00076   std::string JDLParser::simpleJDLvalue(const std::string& attributeValue) const {
00077     const std::string whitespaces(" \t\f\v\n\r");
00078     const size_t last_pos = attributeValue.find_last_of("\"");
00079 
00080     // If the text is not between quotation marks, then return with the original form
00081     if (attributeValue.substr(attributeValue.find_first_not_of(whitespaces), 1) != "\"" || last_pos == std::string::npos)
00082       return trim(attributeValue);
00083     // Else remove the marks and return with the quotation's content
00084     else
00085       return attributeValue.substr(attributeValue.find_first_of("\"") + 1, last_pos - attributeValue.find_first_of("\"") - 1);
00086   }
00087 
00088   std::list<std::string> JDLParser::listJDLvalue(const std::string& attributeValue, std::pair<char, char> brackets, char lineEnd) const {
00089     std::list<std::string> elements;
00090     unsigned long first_bracket = attributeValue.find_first_of(brackets.first);
00091     if (first_bracket == std::string::npos) {
00092       elements.push_back(simpleJDLvalue(attributeValue));
00093       return elements;
00094     }
00095     unsigned long last_bracket = attributeValue.find_last_of(brackets.second);
00096     if (last_bracket == std::string::npos) {
00097       elements.push_back(simpleJDLvalue(attributeValue));
00098       return elements;
00099     }
00100     std::list<std::string> listElements;
00101     tokenize(attributeValue.substr(first_bracket + 1,
00102                                    last_bracket - first_bracket - 1),
00103              listElements, tostring(lineEnd));
00104     for (std::list<std::string>::const_iterator it = listElements.begin();
00105          it != listElements.end(); it++)
00106       elements.push_back(simpleJDLvalue(*it));
00107     return elements;
00108   }
00109 
00110   bool JDLParser::handleJDLattribute(const std::string& attributeName_,
00111                                      const std::string& attributeValue,
00112                                      JobDescription& job) const {
00113     // To do the attributes name case-insensitive do them lowercase and remove the quotiation marks
00114     std::string attributeName = lower(attributeName_);
00115     if (attributeName == "type") {
00116       std::string value = lower(simpleJDLvalue(attributeValue));
00117       if (value == "job")
00118         return true;
00119       if (value == "dag") {
00120         logger.msg(VERBOSE, "[JDLParser] This kind of JDL decriptor is not supported yet: %s", value);
00121         return false;  // This kind of JDL decriptor is not supported yet
00122       }
00123       if (value == "collection") {
00124         logger.msg(VERBOSE, "[JDLParser] This kind of JDL decriptor is not supported yet: %s", value);
00125         return false;  // This kind of JDL decriptor is not supported yet
00126       }
00127       logger.msg(VERBOSE, "[JDLParser] Attribute name: %s, has unknown value: %s", attributeName, value);
00128       return false;    // Unknown attribute value - error
00129     }
00130     else if (attributeName == "jobtype")
00131       return true;     // Skip this attribute
00132     else if (attributeName == "executable") {
00133       job.Application.Executable.Name = simpleJDLvalue(attributeValue);
00134       return true;
00135     }
00136     else if (attributeName == "arguments") {
00137       tokenize(simpleJDLvalue(attributeValue), job.Application.Executable.Argument);
00138       return true;
00139     }
00140     else if (attributeName == "stdinput") {
00141       job.Application.Input = simpleJDLvalue(attributeValue);
00142       return true;
00143     }
00144     else if (attributeName == "stdoutput") {
00145       job.Application.Output = simpleJDLvalue(attributeValue);
00146       return true;
00147     }
00148     else if (attributeName == "stderror") {
00149       job.Application.Error = simpleJDLvalue(attributeValue);
00150       return true;
00151     }
00152     else if (attributeName == "inputsandbox") {
00153       std::list<std::string> inputfiles = listJDLvalue(attributeValue);
00154       for (std::list<std::string>::const_iterator it = inputfiles.begin();
00155            it != inputfiles.end(); it++) {
00156         FileType file;
00157         const std::size_t pos = it->find_last_of('/');
00158         file.Name = (pos == std::string::npos ? *it : it->substr(pos+1));
00159         DataSourceType source;
00160         source.URI = *it;
00161         if (!source.URI)
00162           return false;
00163         source.Threads = -1;
00164         file.Source.push_back(source);
00165         // Initializing these variables
00166         file.KeepData = false;
00167         file.IsExecutable = false;
00168         file.DownloadToCache = false;
00169         job.DataStaging.File.push_back(file);
00170       }
00171       return true;
00172     }
00173     else if (attributeName == "inputsandboxbaseuri") {
00174       for (std::list<FileType>::iterator it = job.DataStaging.File.begin();
00175            it != job.DataStaging.File.end(); it++)
00176         /* Since JDL does not have support for multiple locations the size of
00177          * the Source member is exactly 1.
00178          */
00179         if (!it->Source.empty() && !it->Source.front().URI)
00180           it->Source.front().URI = simpleJDLvalue(attributeValue);
00181       for (std::list<DirectoryType>::iterator it = job.DataStaging.Directory.begin();
00182            it != job.DataStaging.Directory.end(); it++)
00183         if (!it->Source.empty() && !it->Source.front().URI)
00184           it->Source.front().URI = simpleJDLvalue(attributeValue);
00185       return true;
00186     }
00187     else if (attributeName == "outputsandbox") {
00188       std::list<std::string> outputfiles = listJDLvalue(attributeValue);
00189       for (std::list<std::string>::const_iterator it = outputfiles.begin();
00190            it != outputfiles.end(); it++) {
00191         FileType file;
00192         file.Name = *it;
00193         DataTargetType target;
00194         target.URI = *it;
00195         if (!target.URI)
00196           return false;
00197         target.Threads = -1;
00198         target.Mandatory = false;
00199         target.NeededReplica = -1;
00200         file.Target.push_back(target);
00201         // Initializing these variables
00202         file.KeepData = false;
00203         file.IsExecutable = false;
00204         file.DownloadToCache = false;
00205         job.DataStaging.File.push_back(file);
00206       }
00207       return true;
00208     }
00209     else if (attributeName == "outputsandboxdesturi") {
00210       std::list<std::string> value = listJDLvalue(attributeValue);
00211       std::list<std::string>::iterator i = value.begin();
00212       for (std::list<FileType>::iterator it = job.DataStaging.File.begin();
00213            it != job.DataStaging.File.end(); it++) {
00214         if (it->Target.empty())
00215           continue;
00216         if (i != value.end()) {
00217           URL url = *i;
00218           if (url.Protocol() == "gsiftp" && url.Host() == "localhost") {
00219             /* Specifying the local grid ftp server (local to CREAM),
00220              * is the "same", in ARC analogy, to specify the output
00221              * files being user downloadable files. Upon finished job
00222              * execution CREAM will copy outputfiles to the specified
00223              * destination, it does not support storing them at the
00224              * working directory of the job for later retrieval. Instead
00225              * the local grid ftp server to CREAM can be specified.
00226              */
00227             url.ChangeProtocol("file");
00228             url.ChangeHost("");
00229           }
00230           it->Target.front().URI = url;
00231           it->KeepData = (it->Target.front().URI.Protocol() == "file");
00232           i++;
00233         }
00234         else {
00235           logger.msg(VERBOSE, "Not enough outputsandboxdesturi elements!");
00236           return false;
00237         }
00238       }
00239       return true;
00240     }
00241 /*
00242  * The parsing of the outputsandboxbasedesturi does not work as intended.
00243  * Either it should be unsupported (which it is now) or else it should
00244  * be implemented correctly.
00245     else if (attributeName == "outputsandboxbasedesturi") {
00246       for (std::list<FileType>::iterator it = job.DataStaging.File.begin();
00247            it != job.DataStaging.File.end(); it++)
00248         if (!it->Target.empty() && !it->Target.front().URI) {
00249           it->Target.front().URI = simpleJDLvalue(attributeValue);
00250       for (std::list<DirectoryType>::iterator it = job.DataStaging.Directory.begin();
00251            it != job.DataStaging.Directory.end(); it++)
00252         if (!it->Target.empty() && !it->Target.front().URI)
00253           it->Target.front().URI = simpleJDLvalue(attributeValue);
00254       return true;
00255     }
00256 */
00257     else if (attributeName == "prologue") {
00258       job.Application.Prologue.Name = simpleJDLvalue(attributeValue);
00259       return true;
00260     }
00261     else if (attributeName == "prologuearguments") {
00262       tokenize(simpleJDLvalue(attributeValue), job.Application.Prologue.Argument);
00263       return true;
00264     }
00265     else if (attributeName == "epilogue") {
00266       job.Application.Epilogue.Name = simpleJDLvalue(attributeValue);
00267       return true;
00268     }
00269     else if (attributeName == "epiloguearguments") {
00270       tokenize(simpleJDLvalue(attributeValue), job.Application.Epilogue.Argument);
00271       return true;
00272     }
00273     else if (attributeName == "allowzippedisb") {
00274       // Not supported yet, only store it
00275       job.JDL_elements["AllowZippedISB"] = simpleJDLvalue(attributeValue);
00276       return true;
00277     }
00278     else if (attributeName == "zippedisb") {
00279       // Not supported yet, only store it
00280       job.JDL_elements["ZippedISB"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00281       return true;
00282     }
00283     else if (attributeName == "expirytime") {
00284       job.Application.ExpiryTime = Time(stringtol(simpleJDLvalue(attributeValue)));
00285       return true;
00286     }
00287     else if (attributeName == "environment") {
00288       std::list<std::string> variables = listJDLvalue(attributeValue);
00289       for (std::list<std::string>::const_iterator it = variables.begin();
00290            it != variables.end(); it++) {
00291         std::string::size_type equal_pos = it->find('=');
00292         if (equal_pos != std::string::npos) {
00293           job.Application.Environment.push_back(
00294             std::pair<std::string, std::string>(
00295               trim(it->substr(0, equal_pos)),
00296               trim(it->substr(equal_pos + 1))));
00297         }
00298         else {
00299           logger.msg(VERBOSE, "[JDLParser] Environment variable has been defined without any equal sign.");
00300           return false;
00301         }
00302       }
00303       return true;
00304     }
00305     else if (attributeName == "perusalfileenable") {
00306       // Not supported yet, only store it
00307       job.JDL_elements["PerusalFileEnable"] = simpleJDLvalue(attributeValue);
00308       return true;
00309     }
00310     else if (attributeName == "perusaltimeinterval") {
00311       // Not supported yet, only store it
00312       job.JDL_elements["PerusalTimeInterval"] = simpleJDLvalue(attributeValue);
00313       return true;
00314     }
00315     else if (attributeName == "perusalfilesdesturi") {
00316       // Not supported yet, only store it
00317       job.JDL_elements["PerusalFilesDestURI"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00318       return true;
00319     }
00320     else if (attributeName == "inputdata")
00321       // Not supported yet
00322       // will be soon deprecated
00323       return true;
00324     else if (attributeName == "outputdata")
00325       // Not supported yet
00326       // will be soon deprecated
00327       return true;
00328     else if (attributeName == "storageindex")
00329       // Not supported yet
00330       // will be soon deprecated
00331       return true;
00332     else if (attributeName == "datacatalog")
00333       // Not supported yet
00334       // will be soon deprecated
00335       return true;
00336     else if (attributeName == "datarequirements") {
00337       // Not supported yet, only store it
00338       job.JDL_elements["DataRequirements"] = simpleJDLvalue(attributeValue);
00339       return true;
00340     }
00341     else if (attributeName == "dataaccessprotocol") {
00342       // Not supported yet, only store it
00343       job.JDL_elements["DataAccessProtocol"] = simpleJDLvalue(attributeValue);
00344       return true;
00345     }
00346     else if (attributeName == "virtualorganisation") {
00347       job.Identification.JobVOName = simpleJDLvalue(attributeValue);
00348       return true;
00349     }
00350     else if (attributeName == "queuename") {
00351         if (job.Resources.CandidateTarget.empty()) {
00352           ResourceTargetType candidateTarget;
00353           candidateTarget.EndPointURL = URL();
00354           candidateTarget.QueueName = simpleJDLvalue(attributeValue);
00355           job.Resources.CandidateTarget.push_back(candidateTarget);
00356         }
00357         else
00358           job.Resources.CandidateTarget.front().QueueName = simpleJDLvalue(attributeValue);
00359       return true;
00360     }
00361     else if (attributeName == "batchsystem") {
00362       job.JDL_elements["batchsystem"] = simpleJDLvalue(attributeValue);
00363       return true;
00364     }
00365     else if (attributeName == "retrycount") {
00366       const int count = stringtoi(simpleJDLvalue(attributeValue));
00367       if (job.Application.Rerun < count)
00368         job.Application.Rerun = count;
00369       return true;
00370     }
00371     else if (attributeName == "shallowretrycount") {
00372       const int count = stringtoi(simpleJDLvalue(attributeValue));
00373       if (job.Application.Rerun < count)
00374         job.Application.Rerun = count;
00375       return true;
00376     }
00377     else if (attributeName == "lbaddress") {
00378       // Not supported yet, only store it
00379       job.JDL_elements["LBAddress"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00380       return true;
00381     }
00382     else if (attributeName == "myproxyserver") {
00383       URL url(simpleJDLvalue(attributeValue));
00384       if (!url)
00385         return false;
00386       job.Application.CredentialService.push_back(url);
00387       return true;
00388     }
00389     else if (attributeName == "hlrlocation") {
00390       // Not supported yet, only store it
00391       job.JDL_elements["HLRLocation"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00392       return true;
00393     }
00394     else if (attributeName == "jobprovenance") {
00395       // Not supported yet, only store it
00396       job.JDL_elements["JobProvenance"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00397       return true;
00398     }
00399     else if (attributeName == "nodenumber") {
00400       // Not supported yet, only store it
00401       job.JDL_elements["NodeNumber"] = simpleJDLvalue(attributeValue);
00402       return true;
00403     }
00404     else if (attributeName == "jobsteps")
00405       // Not supported yet
00406       // will be soon deprecated
00407       return true;
00408     else if (attributeName == "currentstep")
00409       // Not supported yet
00410       // will be soon deprecated
00411       return true;
00412     else if (attributeName == "jobstate")
00413       // Not supported yet
00414       // will be soon deprecated
00415       return true;
00416     else if (attributeName == "listenerport") {
00417       // Not supported yet, only store it
00418       job.JDL_elements["ListenerPort"] = simpleJDLvalue(attributeValue);
00419       return true;
00420     }
00421     else if (attributeName == "listenerhost") {
00422       // Not supported yet, only store it
00423       job.JDL_elements["ListenerHost"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00424       return true;
00425     }
00426     else if (attributeName == "listenerpipename") {
00427       // Not supported yet, only store it
00428       job.JDL_elements["ListenerPipeName"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00429       return true;
00430     }
00431     else if (attributeName == "requirements") {
00432       // It's too complicated to determinize the right conditions, because the definition language is
00433       // LRMS specific.
00434       // Only store it.
00435       job.JDL_elements["Requirements"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00436       return true;
00437     }
00438     else if (attributeName == "rank") {
00439       job.JobMeta.Rank = simpleJDLvalue(attributeValue);
00440       return true;
00441     }
00442     else if (attributeName == "fuzzyrank") {
00443       job.JobMeta.FuzzyRank = (upper(simpleJDLvalue(attributeValue)) == "TRUE");
00444       return true;
00445     }
00446     else if (attributeName == "usertags") {
00447       job.Identification.UserTag = listJDLvalue(attributeValue, std::make_pair('[', ']'), ';');
00448       return true;
00449     }
00450     else if (attributeName == "outputse") {
00451       // Not supported yet, only store it
00452       job.JDL_elements["OutputSE"] = "\"" + simpleJDLvalue(attributeValue) + "\"";
00453       return true;
00454     }
00455 
00456     logger.msg(WARNING, "[JDL Parser]: Unknown attribute name: \'%s\', with value: %s", attributeName, attributeValue);
00457     return true;
00458   }
00459 
00460   std::string JDLParser::generateOutputList(const std::string& attribute, const std::list<std::string>& list, std::pair<char, char> brackets, char lineEnd) const {
00461     const std::string space = "             "; // 13 spaces seems to be standard padding.
00462     std::ostringstream output;
00463     output << "  " << attribute << " = " << brackets.first << std::endl;
00464     for (std::list<std::string>::const_iterator it = list.begin();
00465          it != list.end(); it++) {
00466       if (it != list.begin())
00467         output << lineEnd << std::endl;
00468       output << space << "\"" << *it << "\"";
00469     }
00470 
00471     output << std::endl << space << brackets.second << ";" << std::endl;
00472     return output.str();
00473   }
00474 
00475   JobDescription JDLParser::Parse(const std::string& source) const {
00476     unsigned long first = source.find_first_of("[");
00477     unsigned long last = source.find_last_of("]");
00478     if (first == std::string::npos || last == std::string::npos) {
00479       logger.msg(VERBOSE, "[JDLParser] There is at least one necessary ruler character missing. ('[' or ']')");
00480       return JobDescription();
00481     }
00482     std::string input_text = source.substr(first + 1, last - first - 1);
00483 
00484     //Remove multiline comments
00485     unsigned long comment_start = 0;
00486     while ((comment_start = input_text.find("/*", comment_start)) != std::string::npos)
00487       input_text.erase(input_text.begin() + comment_start, input_text.begin() + input_text.find("*/", comment_start) + 2);
00488 
00489     std::string wcpy = "";
00490     std::list<std::string> lines;
00491     tokenize(input_text, lines, "\n");
00492     for (std::list<std::string>::iterator it = lines.begin();
00493          it != lines.end();) {
00494       // Remove empty lines
00495       const std::string trimmed_line = trim(*it);
00496       if (trimmed_line.length() == 0)
00497         it = lines.erase(it);
00498       // Remove lines starts with '#' - Comments
00499       else if (trimmed_line.length() >= 1 && trimmed_line.substr(0, 1) == "#")
00500         it = lines.erase(it);
00501       // Remove lines starts with '//' - Comments
00502       else if (trimmed_line.length() >= 2 && trimmed_line.substr(0, 2) == "//")
00503         it = lines.erase(it);
00504       else {
00505         wcpy += *it + "\n";
00506         it++;
00507       }
00508     }
00509 
00510     if (!splitJDL(wcpy, lines)) {
00511       logger.msg(VERBOSE, "[JDLParser] Syntax error found during the split function.");
00512       return JobDescription();
00513     }
00514     if (lines.size() <= 0) {
00515       logger.msg(VERBOSE, "[JDLParser] Lines count is zero or other funny error has occurred.");
00516       return JobDescription();
00517     }
00518 
00519     JobDescription job;
00520 
00521     for (std::list<std::string>::iterator it = lines.begin();
00522          it != lines.end(); it++) {
00523       const size_t equal_pos = it->find_first_of("=");
00524       if (equal_pos == std::string::npos) {
00525         logger.msg(VERBOSE, "[JDLParser] JDL syntax error. There is at least one equal sign missing where it would be expected.");
00526         return JobDescription();
00527       }
00528       if (!handleJDLattribute(trim(it->substr(0, equal_pos)), trim(it->substr(equal_pos + 1)), job))
00529         return JobDescription();
00530     }
00531     return job;
00532   }
00533 
00534   std::string JDLParser::UnParse(const JobDescription& job) const {
00535     std::string product;
00536     product = "[\n  Type = \"job\";\n";
00537 
00538     product += ADDJDLSTRING(job.Application.Executable.Name, "Executable");
00539     if (!job.Application.Executable.Argument.empty()) {
00540       product += "  Arguments = \"";
00541       for (std::list<std::string>::const_iterator it = job.Application.Executable.Argument.begin();
00542            it != job.Application.Executable.Argument.end(); it++) {
00543         if (it != job.Application.Executable.Argument.begin())
00544           product += " ";
00545         product += *it;
00546       }
00547       product += "\";\n";
00548     }
00549 
00550     product += ADDJDLSTRING(job.Application.Input, "StdInput");
00551     product += ADDJDLSTRING(job.Application.Output, "StdOutput");
00552     product += ADDJDLSTRING(job.Application.Error, "StdError");
00553     product += ADDJDLSTRING(job.Identification.JobVOName, "VirtualOrganisation");
00554 
00555     if (!job.Application.Environment.empty()) {
00556       std::list<std::string> environment;
00557       for (std::list< std::pair<std::string, std::string> >::const_iterator it = job.Application.Environment.begin();
00558            it != job.Application.Environment.end(); it++) {
00559         environment.push_back(it->first + " = " + it->second);
00560       }
00561 
00562       if (!environment.empty())
00563         product += generateOutputList("Environment", environment);
00564     }
00565 
00566     product += ADDJDLSTRING(job.Application.Prologue.Name, "Prologue");
00567     if (!job.Application.Prologue.Argument.empty()) {
00568       product += "  PrologueArguments = \"";
00569       for (std::list<std::string>::const_iterator iter = job.Application.Prologue.Argument.begin();
00570            iter != job.Application.Prologue.Argument.end(); iter++) {
00571         if (iter != job.Application.Prologue.Argument.begin())
00572           product += " ";
00573         product += *iter;
00574       }
00575       product += "\";\n";
00576     }
00577 
00578     product += ADDJDLSTRING(job.Application.Epilogue.Name, "Epilogue");
00579     if (!job.Application.Epilogue.Argument.empty()) {
00580       product += "  EpilogueArguments = \"";
00581       for (std::list<std::string>::const_iterator iter = job.Application.Epilogue.Argument.begin();
00582            iter != job.Application.Epilogue.Argument.end(); iter++) {
00583         if (iter != job.Application.Epilogue.Argument.begin())
00584           product += " ";
00585         product += *iter;
00586       }
00587       product += "\";\n";
00588     }
00589 
00590     if (!job.Application.Executable.Name.empty() ||
00591         !job.DataStaging.File.empty() ||
00592         !job.Application.Input.empty() ||
00593         !job.Application.Output.empty() ||
00594         !job.Application.Error.empty()) {
00595 
00596       bool addExecutable = !job.Application.Executable.Name.empty() && !Glib::path_is_absolute(job.Application.Executable.Name);
00597       bool addInput      = !job.Application.Input.empty();
00598       bool addOutput     = !job.Application.Output.empty();
00599       bool addError      = !job.Application.Error.empty();
00600 
00601       std::list<std::string> inputSandboxList;
00602       std::list<std::string> outputSandboxList;
00603       std::list<std::string> outputSandboxDestURIList;
00604       for (std::list<FileType>::const_iterator it = job.DataStaging.File.begin();
00605            it != job.DataStaging.File.end(); it++) {
00606         /* Since JDL does not have support for multiple locations only the first
00607          * location will be added.
00608          */
00609         if (!it->Source.empty())
00610           inputSandboxList.push_back(it->Source.front().URI ? it->Source.front().URI.fullstr() : it->Name);
00611         if (!it->Target.empty() && it->Target.front().URI || it->KeepData) {
00612           outputSandboxList.push_back(it->Name);
00613           /* User downloadable files should go to the local grid ftp
00614            * server (local to CREAM). See comments on the parsing of the
00615            * outputsandboxdesturi attribute above.
00616            */
00617           const std::string uri_tmp = (it->Target.empty() || it->Target.front().URI.Protocol() == "file" ?
00618                                        "gsiftp://localhost/" + it->Name :
00619                                        it->Target.front().URI.fullstr());
00620           outputSandboxDestURIList.push_back(uri_tmp);
00621         }
00622 
00623         addExecutable &= (it->Name != job.Application.Executable.Name);
00624         addInput      &= (it->Name != job.Application.Input);
00625         addOutput     &= (it->Name != job.Application.Output);
00626         addError      &= (it->Name != job.Application.Error);
00627       }
00628 
00629       if (addExecutable)
00630         inputSandboxList.push_back(job.Application.Executable.Name);
00631       if (addInput)
00632         inputSandboxList.push_back(job.Application.Input);
00633       if (addOutput) {
00634         outputSandboxList.push_back(job.Application.Output);
00635         outputSandboxDestURIList.push_back(job.Application.Output);
00636       }
00637       if (addError) {
00638         outputSandboxList.push_back(job.Application.Error);
00639         outputSandboxDestURIList.push_back(job.Application.Error);
00640       }
00641 
00642       if (!inputSandboxList.empty())
00643         product += generateOutputList("InputSandbox", inputSandboxList);
00644       if (!outputSandboxList.empty())
00645         product += generateOutputList("OutputSandbox", outputSandboxList);
00646       if (!outputSandboxDestURIList.empty())
00647         product += generateOutputList("OutputSandboxDestURI", outputSandboxDestURIList);
00648     }
00649 
00650     if (!job.Resources.CandidateTarget.empty() &&
00651         !job.Resources.CandidateTarget.front().QueueName.empty()) {
00652       product += "  QueueName = \"";
00653       product += job.Resources.CandidateTarget.front().QueueName;
00654       product += "\";\n";
00655     }
00656 
00657     product += ADDJDLNUMBER(job.Application.Rerun, "RetryCount");
00658     product += ADDJDLNUMBER(job.Application.Rerun, "ShallowRetryCount");
00659     product += ADDJDLNUMBER(job.Application.ExpiryTime.GetTime(), "ExpiryTime");
00660 
00661     if (!job.Application.CredentialService.empty() &&
00662         job.Application.CredentialService.front()) {
00663       product += "  MyProxyServer = \"";
00664       product += job.Application.CredentialService.front().fullstr();
00665       product += "\";\n";
00666     }
00667 
00668     product += ADDJDLSTRING(job.JobMeta.Rank, "Rank");
00669 
00670     if (job.JobMeta.FuzzyRank)
00671       product += "  FuzzyRank = true;\n";
00672 
00673     if (!job.Identification.UserTag.empty())
00674       product += generateOutputList("UserTags", job.Identification.UserTag, std::pair<char, char>('[', ']'), ';');
00675 
00676     if (!job.JDL_elements.empty()) {
00677       std::map<std::string, std::string>::const_iterator it;
00678       for (it = job.JDL_elements.begin(); it != job.JDL_elements.end(); it++) {
00679         product += "  ";
00680         product += it->first;
00681         product += " = \"";
00682         product += it->second;
00683         product += "\";\n";
00684       }
00685     }
00686     product += "]";
00687 
00688     return product;
00689   }
00690 
00691 } // namespace Arc