Update to ARC 4.1.0 master
authorSzigeti Gábor <szigeti@portal.grid.niif.hu>
Fri, 25 Jul 2014 11:47:03 +0000 (13:47 +0200)
committerSzigeti Gábor <szigeti@portal.grid.niif.hu>
Fri, 25 Jul 2014 11:47:03 +0000 (13:47 +0200)
Manifest.txt
ext/arc_get.cpp
ext/arc_kill.cpp
ext/arc_libs.h
ext/arc_stat.cpp
ext/arc_submit.cpp
ext/extconf.rb
ext/utils.cpp [new file with mode: 0644]
ext/utils.h [new file with mode: 0644]

index 9a0ea21..af02271 100644 (file)
@@ -30,4 +30,5 @@ ext/arcclientc.h
 ext/common_utils.cpp
 ext/common_utils.h
 ext/logger.h
 ext/common_utils.cpp
 ext/common_utils.h
 ext/logger.h
-
+ext/utils.cpp
+ext/utils.h
index bfcdff7..1f22a2c 100644 (file)
 #include <iostream>
 #include <list>
 #include <string>
 #include <iostream>
 #include <list>
 #include <string>
+#include <sys/stat.h>
 #include "arc_libs.h"
 
 #include "arc_libs.h"
 
+#include "utils.h"
 
 int arc_get(int argc, char **argv) {
        
 
 int arc_get(int argc, char **argv) {
        
-       
+  Arc::ArcLocation::Init(argv[0]);
 
 
-       
-       Arc::OptionParser options(istring("[job ...]"),
-                                                         istring("The arcget command is used for "
-                                                                         "retrieving the results from a job."),
-                                                         istring("Argument to -c has the format "
-                                                                         "Flavour:URL e.g.\n"
-                                                                         "ARC0:ldap://grid.tsl.uu.se:2135/"
-                                                                         "nordugrid-cluster-name=grid.tsl.uu.se,"
-                                                                         "Mds-Vo-name=local,o=grid"));
-       
-       
-       std::string joblist;
-       options.AddOption('j', "joblist",
-                                         istring("file containing a list of jobs"),
-                                         istring("filename"),
-                                         joblist);
-       
-       std::list<std::string> clusters;
-       options.AddOption('c', "cluster",
-                                         istring("explicitly select or reject a specific resource"),
-                                         istring("[-]name"),
-                                         clusters);
-       
-       std::list<std::string> status;
-       options.AddOption('s', "status",
-                                         istring("only select jobs whose status is statusstr"),
-                                         istring("statusstr"),
-                                         status);
-       
-       std::string downloaddir;
-       options.AddOption('D', "dir",
-                                         istring("download directory (the job directory will"
-                                                         " be created in this directory)"),
-                                         istring("dirname"),
-                                         downloaddir);
-       
-       bool keep = false;
-       options.AddOption('k', "keep",
-                                         istring("keep the files on the server (do not clean)"),
-                                         keep);
-       
-       int timeout = -1;
-       options.AddOption('t', "timeout", istring("timeout in seconds (default 20)"),
-                                         istring("seconds"), timeout);
-       
-       std::string conffile;
-       options.AddOption('z', "conffile",
-                                         istring("configuration file (default ~/.arc/client.conf)"),
-                                         istring("filename"), conffile);
-       
-       
-       
-       std::list<std::string> jobs = options.Parse(argc, argv);
-       
+  ClientOptions opt(ClientOptions::CO_GET,
+                    istring("[job ...]"),
+                    istring("The arcget command is used for "
+                            "retrieving the results from a job."));
 
 
-               
-               
-       Arc::UserConfig usercfg(conffile, joblist);
-       if (!usercfg) {
-               logger.msg(Arc::ERROR, "Failed configuration initialization");
-               return 1;
-       }
-               
-       if (timeout > 0)
-       usercfg.Timeout(timeout);
-               
-       if (jobs.empty() && clusters.empty()) {
-               logger.msg(Arc::ERROR, "No jobs given");
-               return 1;
-       }
-       
-       if (!jobs.empty())
-               usercfg.ClearSelectedServices();
-       
-       if (!clusters.empty()) {
-               usercfg.ClearSelectedServices();
-               usercfg.AddServices(clusters, Arc::COMPUTING);
-       }
-       
-       Arc::JobSupervisor jobmaster(usercfg, jobs);
-       if (!jobmaster.JobsFound()) {
-               logger.msg(Arc::ERROR, "No jobs");
-               return 1;
-       }
-       std::list<Arc::JobController*> jobcont = jobmaster.GetJobControllers();
-       
-       // If the user specified a joblist on the command line joblist equals
-       // usercfg.JobListFile(). If not use the default, ie. usercfg.JobListFile().
-       if (jobcont.empty()) {
-               logger.msg(Arc::ERROR, "No job controller plugins loaded");
-               return 1;
-       }
-  int result = 0;
-       for (std::list<Arc::JobController*>::iterator it = jobcont.begin();
-                it != jobcont.end(); it++){
-               if (!(*it)->Get(status, downloaddir, keep, false, false)){
-                       result = 1;
-               }
-       }
-       
-       return result;
+  std::list<std::string> jobidentifiers = opt.Parse(argc, argv);
+
+  if (opt.showversion) {
+    std::cout << Arc::IString("%s version %s", "arcget", "4.1.0")
+              << std::endl;
+    return 0;
+  }
+
+  // If debug is specified as argument, it should be set before loading the configuration.
+  if (!opt.debug.empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(opt.debug));
+
+  logger.msg(Arc::VERBOSE, "Running command: %s", opt.GetCommandWithArguments());
+
+  if (opt.show_plugins) {
+    std::list<std::string> types;
+    types.push_back("HED:JobControllerPlugin");
+    showplugins("arcget", types, logger);
+    return 0;
+  }
+
+  Arc::UserConfig usercfg(opt.conffile, opt.joblist);
+  if (!usercfg) {
+    logger.msg(Arc::ERROR, "Failed configuration initialization");
+    return 1;
+  }
+
+  if (!checkproxy(usercfg)) {
+    return 1;
+  }
+
+  if (opt.debug.empty() && !usercfg.Verbosity().empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(usercfg.Verbosity()));
+
+  if (opt.downloaddir.empty()) {
+    if (!usercfg.JobDownloadDirectory().empty()) {
+      opt.downloaddir = usercfg.JobDownloadDirectory();
+      logger.msg(Arc::INFO, "Job download directory from user configuration file: %s ", opt.downloaddir);
+    }
+    else {
+      logger.msg(Arc::INFO, "Job download directory will be created in present working directory. ");
+    }
+  }
+  else {
+    logger.msg(Arc::INFO, "Job download directory: %s ", opt.downloaddir);
+  }
+
+  for (std::list<std::string>::const_iterator it = opt.jobidinfiles.begin(); it != opt.jobidinfiles.end(); it++) {
+    if (!Arc::Job::ReadJobIDsFromFile(*it, jobidentifiers)) {
+      logger.msg(Arc::WARNING, "Cannot read specified jobid file: %s", *it);
+    }
+  }
+
+  if (opt.timeout > 0)
+    usercfg.Timeout(opt.timeout);
+
+  if ((!opt.joblist.empty() || !opt.status.empty()) && jobidentifiers.empty() && opt.clusters.empty())
+    opt.all = true;
+
+  if (jobidentifiers.empty() && opt.clusters.empty() && !opt.all) {
+    logger.msg(Arc::ERROR, "No jobs given");
+    return 1;
+  }
+
+  std::list<std::string> selectedURLs;
+  if (!opt.clusters.empty()) {
+    selectedURLs = getSelectedURLsFromUserConfigAndCommandLine(usercfg, opt.clusters);
+  }
+  std::list<std::string> rejectManagementURLs = getRejectManagementURLsFromUserConfigAndCommandLine(usercfg, opt.rejectmanagement);
+
+  std::list<Arc::Job> jobs;
+  Arc::JobInformationStorage *jobstore = createJobInformationStorage(usercfg);
+  if (jobstore != NULL && !jobstore->IsStorageExisting()) {
+    logger.msg(Arc::ERROR, "Job list file (%s) doesn't exist", usercfg.JobListFile());
+    delete jobstore;
+    return 1;
+  }
+  if (jobstore == NULL ||
+      ( opt.all && !jobstore->ReadAll(jobs, rejectManagementURLs)) ||
+      (!opt.all && !jobstore->Read(jobs, jobidentifiers, selectedURLs, rejectManagementURLs))) {
+    logger.msg(Arc::ERROR, "Unable to read job information from file (%s)", usercfg.JobListFile());
+    delete jobstore;
+    return 1;
+  }
+
+  if (!opt.all) {
+    for (std::list<std::string>::const_iterator itJIdentifier = jobidentifiers.begin();
+         itJIdentifier != jobidentifiers.end(); ++itJIdentifier) {
+      std::cout << Arc::IString("Warning: Job not found in job list: %s", *itJIdentifier) << std::endl;
+    }
+  }
+
+  Arc::JobSupervisor jobmaster(usercfg, jobs);
+
+  jobmaster.Update();
+  jobmaster.SelectValid();
+  if (!opt.status.empty()) {
+    jobmaster.SelectByStatus(opt.status);
+  }
+
+  if (jobmaster.GetSelectedJobs().empty()) {
+    std::cout << Arc::IString("No jobs") << std::endl;
+    delete jobstore;
+    return 1;
+  }
+
+  if(!opt.downloaddir.empty()) {
+    Arc::URL dirpath(opt.downloaddir);
+    if(dirpath.Protocol() == "file") {
+      if(!Arc::DirCreate(dirpath.Path(),S_IRWXU,true)) {
+        std::string errstr = Arc::StrError();
+        logger.msg(Arc::ERROR, "Unable to create directory for storing results (%s) - %s", dirpath.Path(), errstr);
+        return 1;
+      }
+    }
+  }
+  std::list<std::string> downloaddirectories;
+  int retval = (int)!jobmaster.Retrieve(opt.downloaddir, opt.usejobname, opt.forcedownload, downloaddirectories);
+
+  for (std::list<std::string>::const_iterator it = downloaddirectories.begin();
+       it != downloaddirectories.end(); ++it) {
+    std::cout << Arc::IString("Results stored at: %s", *it) << std::endl;
+  }
+
+  unsigned int processed_num = jobmaster.GetIDsProcessed().size();
+  unsigned int retrieved_num = downloaddirectories.size();
+  unsigned int cleaned_num = 0;
+
+  if (!opt.keep) {
+    std::list<std::string> retrieved = jobmaster.GetIDsProcessed();
+    // No need to clean selection because retrieved is subset of selected
+    jobmaster.SelectByID(retrieved);
+    if(!jobmaster.Clean()) {
+      std::cout << Arc::IString("Warning: Some jobs were not removed from server") << std::endl;
+      std::cout << Arc::IString("         Use arclean to remove retrieved jobs from job list", usercfg.JobListFile()) << std::endl;
+      retval = 1;
+    }
+    cleaned_num = jobmaster.GetIDsProcessed().size();
+
+    if (!jobstore->Remove(jobmaster.GetIDsProcessed())) {
+      std::cout << Arc::IString("Warning: Failed removing jobs from file (%s)", usercfg.JobListFile()) << std::endl;
+      std::cout << Arc::IString("         Use arclean to remove retrieved jobs from job list", usercfg.JobListFile()) << std::endl;
+      retval = 1;
+    }
+
+    std::cout << Arc::IString("Jobs processed: %d, successfully retrieved: %d, successfully cleaned: %d", processed_num, retrieved_num, cleaned_num) << std::endl;
+
+  } else {
+
+    std::cout << Arc::IString("Jobs processed: %d, successfully retrieved: %d", processed_num, retrieved_num) << std::endl;
+
+  }
+  delete jobstore;
+
+  return retval;       
 }
 }
index c0a098f..31cc33f 100644 (file)
 #include <algorithm>
 #include "arc_libs.h"
 
 #include <algorithm>
 #include "arc_libs.h"
 
+#include "utils.h"
+
 int  arc_kill(int argc, char **argv) {
 
 int  arc_kill(int argc, char **argv) {
 
-  Arc::OptionParser options(istring("[job ...]"),
-                            istring("The arckill command is used to kill "
-                                    "running jobs."),
-                            istring("Argument to -c has the format "
-                                    "Flavour:URL e.g.\n"
-                                    "ARC0:ldap://grid.tsl.uu.se:2135/"
-                                    "nordugrid-cluster-name=grid.tsl.uu.se,"
-                                    "Mds-Vo-name=local,o=grid"));
-
-  bool all = false;
-  options.AddOption('a', "all",
-                    istring("all jobs"),
-                    all);
-
-  std::string joblist;
-  options.AddOption('j', "joblist",
-                    istring("file containing a list of jobs"),
-                    istring("filename"),
-                    joblist);
-
-  std::list<std::string> clusters;
-  options.AddOption('c', "cluster",
-                    istring("explicitly select or reject a specific resource"),
-                    istring("[-]name"),
-                    clusters);
-
-  std::list<std::string> status;
-  options.AddOption('s', "status",
-                    istring("only select jobs whose status is statusstr"),
-                    istring("statusstr"),
-                    status);
-
-  bool keep = false;
-  options.AddOption('k', "keep",
-                    istring("keep the files on the server (do not clean)"),
-                    keep);
-
-  int timeout = -1;
-  options.AddOption('t', "timeout", istring("timeout in seconds (default 20)"),
-                    istring("seconds"), timeout);
-
-  std::string conffile;
-  options.AddOption('z', "conffile",
-                    istring("configuration file (default ~/.arc/client.conf)"),
-                    istring("filename"), conffile);
-
-  std::list<std::string> jobs = options.Parse(argc, argv);
-
-
-  Arc::UserConfig usercfg(conffile, joblist);
+  Arc::ArcLocation::Init(argv[0]);
+
+  ClientOptions opt(ClientOptions::CO_KILL,
+                    istring("[job ...]"),
+                    istring("The arckill command is used to kill "
+                            "running jobs."));
+
+  std::list<std::string> jobidentifiers = opt.Parse(argc, argv);
+
+  if (opt.showversion) {
+    std::cout << Arc::IString("%s version %s", "arckill", "4.1.0")
+              << std::endl;
+    return 0;
+  }
+
+  // If debug is specified as argument, it should be set before loading the configuration.
+  if (!opt.debug.empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(opt.debug));
+
+  logger.msg(Arc::VERBOSE, "Running command: %s", opt.GetCommandWithArguments());
+
+  if (opt.show_plugins) {
+    std::list<std::string> types;
+    types.push_back("HED:JobControllerPlugin");
+    showplugins("arckill", types, logger);
+    return 0;
+  }
+
+  Arc::UserConfig usercfg(opt.conffile, opt.joblist);
   if (!usercfg) {
     logger.msg(Arc::ERROR, "Failed configuration initialization");
     return 1;
   }
 
   if (!usercfg) {
     logger.msg(Arc::ERROR, "Failed configuration initialization");
     return 1;
   }
 
-  if (timeout > 0)
-    usercfg.Timeout(timeout);
+  if (!checkproxy(usercfg)) {
+    return 1;
+  }
+
+  if (opt.debug.empty() && !usercfg.Verbosity().empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(usercfg.Verbosity()));
 
 
-  if ((!joblist.empty() || !status.empty()) && jobs.empty() && clusters.empty()){
-    all = true;
-    logger.msg(Arc::DEBUG, "Implicit all turned on");
+  for (std::list<std::string>::const_iterator it = opt.jobidinfiles.begin(); it != opt.jobidinfiles.end(); it++) {
+    if (!Arc::Job::ReadJobIDsFromFile(*it, jobidentifiers)) {
+      logger.msg(Arc::WARNING, "Cannot read specified jobid file: %s", *it);
+    }
   }
 
   }
 
-  if (jobs.empty() && clusters.empty() && !all) {
+  if (opt.timeout > 0)
+    usercfg.Timeout(opt.timeout);
+
+  if ((!opt.joblist.empty() || !opt.status.empty()) && jobidentifiers.empty() && opt.clusters.empty())
+    opt.all = true;
+
+  if (jobidentifiers.empty() && opt.clusters.empty() && !opt.all) {
     logger.msg(Arc::ERROR, "No jobs given");
     return 1;
   }
 
     logger.msg(Arc::ERROR, "No jobs given");
     return 1;
   }
 
-  if (!jobs.empty() || all){
-    usercfg.ClearSelectedServices();
-    logger.msg(Arc::DEBUG, "ClearSelectedServcies was invoked.");
+  std::list<std::string> selectedURLs;
+  if (!opt.clusters.empty()) {
+    selectedURLs = getSelectedURLsFromUserConfigAndCommandLine(usercfg, opt.clusters);
+  }
+  std::list<std::string> rejectManagementURLs = getRejectManagementURLsFromUserConfigAndCommandLine(usercfg, opt.rejectmanagement);
+
+  std::list<Arc::Job> jobs;
+  Arc::JobInformationStorage *jobstore = createJobInformationStorage(usercfg);
+  if (jobstore != NULL && !jobstore->IsStorageExisting()) {
+    logger.msg(Arc::ERROR, "Job list file (%s) doesn't exist", usercfg.JobListFile());
+    delete jobstore;
+    return 1;
+  }
+  if (jobstore == NULL ||
+      ( opt.all && !jobstore->ReadAll(jobs, rejectManagementURLs)) ||
+      (!opt.all && !jobstore->Read(jobs, jobidentifiers, selectedURLs, rejectManagementURLs))) {
+    logger.msg(Arc::ERROR, "Unable to read job information from file (%s)", usercfg.JobListFile());
+    delete jobstore;
+    return 1;
   }
 
   }
 
-  if (!clusters.empty()) {
-    usercfg.ClearSelectedServices();
-    usercfg.AddServices(clusters, Arc::COMPUTING);
+  if (!opt.all) {
+    for (std::list<std::string>::const_iterator itJIDAndName = jobidentifiers.begin();
+         itJIDAndName != jobidentifiers.end(); ++itJIDAndName) {
+      std::cout << Arc::IString("Warning: Job not found in job list: %s", *itJIDAndName) << std::endl;
+    }
   }
 
   }
 
-  // If the user specified a joblist on the command line joblist equals
-  // usercfg.JobListFile(). If not use the default, ie. usercfg.JobListFile().
   Arc::JobSupervisor jobmaster(usercfg, jobs);
   Arc::JobSupervisor jobmaster(usercfg, jobs);
-  if (!jobmaster.JobsFound()) {
-    logger.msg(Arc::ERROR, "No jobs");
-    return 0;
+  jobmaster.Update();
+  jobmaster.SelectValid();
+  if (!opt.status.empty()) {
+    jobmaster.SelectByStatus(opt.status);
   }
   }
-  std::list<Arc::JobController*> jobcont = jobmaster.GetJobControllers();
 
 
-  if (jobcont.empty()) {
-    logger.msg(Arc::ERROR, "No job controller plugins loaded");
+  if (jobmaster.GetSelectedJobs().empty()) {
+    std::cout << Arc::IString("No jobs") << std::endl;
+    delete jobstore;
     return 1;
   }
 
     return 1;
   }
 
-  int retval = 0;
-  for (std::list<Arc::JobController*>::iterator it = jobcont.begin();
-       it != jobcont.end(); it++)
-    if (!(*it)->Kill(status, keep))
+  int retval = (int)!jobmaster.Cancel();
+
+  unsigned int selected_num = jobmaster.GetSelectedJobs().size();
+  unsigned int canceled_num = jobmaster.GetIDsProcessed().size();
+  unsigned int cleaned_num = 0;
+
+  if (!opt.keep) {
+    std::list<std::string> canceled = jobmaster.GetIDsProcessed();
+    // No need to clean selection because retrieved is subset of selected
+    jobmaster.SelectByID(canceled);
+    if(!jobmaster.Clean()) {
+      std::cout << Arc::IString("Warning: Some jobs were not removed from server") << std::endl;
+      std::cout << Arc::IString("         Use arclean to remove retrieved jobs from job list", usercfg.JobListFile()) << std::endl;
       retval = 1;
       retval = 1;
+    }
+    cleaned_num = jobmaster.GetIDsProcessed().size();
+
+    if (!jobstore->Remove(jobmaster.GetIDsProcessed())) {
+      std::cout << Arc::IString("Warning: Failed removing jobs from file (%s)", usercfg.JobListFile()) << std::endl;
+      std::cout << Arc::IString("         Run 'arcclean -s Undefined' to remove killed jobs from job list", usercfg.JobListFile()) << std::endl;
+      retval = 1;
+    }
+    std::cout << Arc::IString("Jobs processed: %d, successfully killed: %d, successfully cleaned: %d", selected_num, canceled_num, cleaned_num) << std::endl;
+  } else {
+    std::cout << Arc::IString("Jobs processed: %d, successfully killed: %d", selected_num, canceled_num) << std::endl;
+  }
+  delete jobstore;
 
   return retval;
 
   return retval;
-}
\ No newline at end of file
+
+}
index a2ae137..d035b67 100644 (file)
@@ -12,6 +12,7 @@
 #include <arc/ArcLocation.h>
 #include <arc/DateTime.h>
 #include <arc/FileLock.h>
 #include <arc/ArcLocation.h>
 #include <arc/DateTime.h>
 #include <arc/FileLock.h>
+#include <arc/FileUtils.h>
 #include <arc/IString.h>
 #include <arc/Logger.h>
 #include <arc/OptionParser.h>
 #include <arc/IString.h>
 #include <arc/Logger.h>
 #include <arc/OptionParser.h>
 #include <arc/URL.h>
 #include <arc/Utils.h>
 #include <arc/XMLNode.h>
 #include <arc/URL.h>
 #include <arc/Utils.h>
 #include <arc/XMLNode.h>
-#include <arc/client/Submitter.h>
-#include <arc/client/TargetGenerator.h>
-#include <arc/client/JobController.h>
-#include <arc/client/JobDescription.h>
-#include <arc/client/JobSupervisor.h>
+#include <arc/compute/Submitter.h>
+#include <arc/compute/ComputingServiceRetriever.h>
+//#include <arc/client/TargetGenerator.h>
+#include <arc/compute/JobControllerPlugin.h>
+#include <arc/compute/JobDescription.h>
+#include <arc/compute/JobSupervisor.h>
 #include <arc/UserConfig.h>
 #include <arc/UserConfig.h>
-#include <arc/client/Broker.h>
+#include <arc/compute/Broker.h>
+//#include <arc/compute/JobInformationStorage.h>
 
 
-#endif
\ No newline at end of file
+#endif
index a71cc3d..66fcd36 100644 (file)
 #include <algorithm>
 #include "arc_libs.h"
 
 #include <algorithm>
 #include "arc_libs.h"
 
+#include "utils.h"
 char*  arc_stat(int argc, char **argv) {
        
   char* result;
 char*  arc_stat(int argc, char **argv) {
        
   char* result;
-       Arc::OptionParser options(istring("[job ...]"),
-                                                         istring("The arcstat command is used for "
-                                                                         "obtaining the status of jobs that have\n"
-                                                                         "been submitted to Grid enabled resources."),
-                                                         istring("Argument to -c has the format "
-                                                                         "Flavour:URL e.g.\n"
-                                                                         "ARC0:ldap://grid.tsl.uu.se:2135/"
-                                                                         "nordugrid-cluster-name=grid.tsl.uu.se,"
-                                                                         "Mds-Vo-name=local,o=grid"));
-       
-       
-       std::string joblist;
-       options.AddOption('j', "joblist",
-                                         istring("file containing a list of jobs"),
-                                         istring("filename"),
-                                         joblist);
-       
-       std::list<std::string> clusters;
-       options.AddOption('c', "cluster",
-                                         istring("explicitly select or reject a specific resource"),
-                                         istring("[-]name"),
-                                         clusters);
-       
-       
-       int timeout = -1;
-       options.AddOption('t', "timeout", istring("timeout in seconds (default 20)"),
-                                         istring("seconds"), timeout);
-       
-       std::string conffile;
-       options.AddOption('z', "conffile",
-                                         istring("configuration file (default ~/.arc/client.conf)"),
-                                         istring("filename"), conffile);
-               
-       
-       std::list<std::string> jobs = options.Parse(argc, argv);
-       
-       
-               
-       Arc::UserConfig usercfg(conffile, joblist);
-       if (!usercfg) {
-               //result  -> message = new_str("Failed configuration initialization");
-               logger.msg(Arc::ERROR, "Failed configuration initialization");
-               return NULL;
-       }
-               
-       if (timeout > 0)
-       usercfg.Timeout(timeout);
-       
+  Arc::ArcLocation::Init(argv[0]);
 
 
+  ClientOptions opt(ClientOptions::CO_STAT,
+                    istring("[job ...]"),
+                    istring("The arcstat command is used for "
+                            "obtaining the status of jobs that have\n"
+                            "been submitted to Grid enabled resources."));
+
+  std::list<std::string> jobidentifiers = opt.Parse(argc, argv);
+
+  if (opt.showversion) {
+    std::cout << Arc::IString("%s version %s", "arcstat", "4.1.0")
+              << std::endl;
+    return NULL;
+  }
+
+  // If debug is specified as argument, it should be set before loading the configuration.
+  if (!opt.debug.empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(opt.debug));
+
+  logger.msg(Arc::VERBOSE, "Running command: %s", opt.GetCommandWithArguments());
+
+  if (opt.show_plugins) {
+    std::list<std::string> types;
+    types.push_back("HED:JobControllerPlugin");
+    showplugins("arcstat", types, logger);
+    return NULL;
+  }
+
+  Arc::UserConfig usercfg(opt.conffile, opt.joblist);
+  if (!usercfg) {
+    logger.msg(Arc::ERROR, "Failed configuration initialization");
+    return NULL;
+  }
+
+  if (opt.debug.empty() && !usercfg.Verbosity().empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(usercfg.Verbosity()));
+
+  for (std::list<std::string>::const_iterator it = opt.jobidinfiles.begin(); it != opt.jobidinfiles.end(); it++) {
+    if (!Arc::Job::ReadJobIDsFromFile(*it, jobidentifiers)) {
+      logger.msg(Arc::WARNING, "Cannot read specified jobid file: %s", *it);
+    }
+  }
+
+  if (opt.timeout > 0)
+    usercfg.Timeout(opt.timeout);
+
+  if (!opt.sort.empty() && !opt.rsort.empty()) {
+    logger.msg(Arc::ERROR, "The 'sort' and 'rsort' flags cannot be specified at the same time.");
+    return NULL;
+  }
+
+  if (!opt.rsort.empty()) {
+    opt.sort = opt.rsort;
+  }
+
+  typedef bool (*JobSorting)(const Arc::Job&, const Arc::Job&);
+  std::map<std::string, JobSorting> orderings;
+  orderings["jobid"] = &Arc::Job::CompareJobID;
+  orderings["submissiontime"] = &Arc::Job::CompareSubmissionTime;
+  orderings["jobname"] = &Arc::Job::CompareJobName;
+
+  if (!opt.sort.empty() && orderings.find(opt.sort) == orderings.end()) {
+    std::cerr << "Jobs cannot be sorted by \"" << opt.sort << "\", the following orderings are supported:" << std::endl;
+    for (std::map<std::string, JobSorting>::const_iterator it = orderings.begin();
+         it != orderings.end(); it++)
+      std::cerr << it->first << std::endl;
+    return NULL;
+  }
+
+  if ((!opt.joblist.empty() || !opt.status.empty()) && jobidentifiers.empty() && opt.clusters.empty())
+    opt.all = true;
+
+  if (jobidentifiers.empty() && opt.clusters.empty() && !opt.all) {
+    logger.msg(Arc::ERROR, "No jobs given");
+    return NULL;
+  }
+  
+  std::list<std::string> selectedURLs;
+  if (!opt.clusters.empty()) {
+    selectedURLs = getSelectedURLsFromUserConfigAndCommandLine(usercfg, opt.clusters);
+  }
+  std::list<std::string> rejectManagementURLs = getRejectManagementURLsFromUserConfigAndCommandLine(usercfg, opt.rejectmanagement);
+  std::list<Arc::Job> jobs;
+  Arc::JobInformationStorage *jobstore = createJobInformationStorage(usercfg);
+  if (jobstore != NULL && !jobstore->IsStorageExisting()) {
+    logger.msg(Arc::ERROR, "Job list file (%s) doesn't exist", usercfg.JobListFile());
+    delete jobstore;
+    return NULL;
+  }
+  if (jobstore == NULL ||
+      ( opt.all && !jobstore->ReadAll(jobs, rejectManagementURLs)) ||
+      (!opt.all && !jobstore->Read(jobs, jobidentifiers, selectedURLs, rejectManagementURLs))) {
+    logger.msg(Arc::ERROR, "Unable to read job information from file (%s)", usercfg.JobListFile());
+    delete jobstore;
+    return NULL;
+  }
+  delete jobstore;
+
+  if (!opt.all) {
+    for (std::list<std::string>::const_iterator itJIDAndName = jobidentifiers.begin();
+         itJIDAndName != jobidentifiers.end(); ++itJIDAndName) {
+      std::cout << Arc::IString("Warning: Job not found in job list: %s", *itJIDAndName) << std::endl;
+    }
+  }
+
+  Arc::JobSupervisor jobmaster(usercfg, jobs);
+  jobmaster.Update();
+  unsigned int queried_num = jobmaster.GetAllJobs().size();
+  if (!opt.status.empty()) {
+    jobmaster.SelectByStatus(opt.status);
+  }
+  if (!opt.show_unavailable) {
+    jobmaster.SelectValid();
+  }
+  jobs = jobmaster.GetSelectedJobs();
+
+  if (queried_num == 0) {
+    std::cout << Arc::IString("No jobs found, try later") << std::endl;
+    return NULL;
+  }
+
+  std::vector<Arc::Job> jobsSortable(jobs.begin(), jobs.end());
+
+  if (!opt.sort.empty()) {
+    opt.rsort.empty() ? std::sort(jobsSortable.begin(),  jobsSortable.end(),  orderings[opt.sort]) :
+                        std::sort(jobsSortable.rbegin(), jobsSortable.rend(), orderings[opt.sort]);
+  }
+
+  for (std::vector<Arc::Job>::const_iterator it = jobsSortable.begin();
+       it != jobsSortable.end(); it++) {
+    // Option 'long' (longlist) takes precedence over option 'print-jobids' (printids)
+//    if (opt.longlist || !opt.printids) {
+      it->SaveToStream(std::cout, opt.longlist);
+//    }
+//    else {
+//      std::cout << it->JobID << std::endl;
+      result = strdup((it->State).GetGeneralState().c_str());
+         
+      return result;
+//    }
+  }
+
+  if (opt.show_unavailable) {
+    jobmaster.SelectValid();
+  }
+  unsigned int returned_info_num = jobmaster.GetSelectedJobs().size();
+
+  std::cout << Arc::IString("Status of %d jobs was queried, %d jobs returned information", queried_num, returned_info_num) << std::endl;
        
        
-       if (!jobs.empty())
-       usercfg.ClearSelectedServices();
-       
-       if (!clusters.empty()) {
-               usercfg.ClearSelectedServices();
-               usercfg.AddServices(clusters, Arc::COMPUTING);
-       }
-       
-       Arc::JobSupervisor jobmaster(usercfg, jobs);
-       if (!jobmaster.JobsFound()) {
-               //result -> message = new_str("No jobs");
-    logger.msg(Arc::INFO, "No jobs");
-               return NULL;
-       }
-       std::list<Arc::JobController*> jobcont = jobmaster.GetJobControllers();
-       
-       if (jobcont.empty()) {
-               //result -> message = new_str("No job controller plugins loaded");
-    logger.msg(Arc::INFO, "No job controller plugins loaded");
-               return NULL;
-       }
-       
-       if (jobcont.size() != 1){
-               //result -> message = new_str("Too many jobs found");
-    logger.msg(Arc::ERROR, "Too many jobs found");
-               return NULL;
-       } 
-       Arc::JobController* it = jobcont.front();
-       
-       it->GetJobInformation();
-       
-       std::list<Arc::Job> jobs_list = it->GetJobs();
-       
-       if (jobs_list.size() != 1) {
-               //result -> message = new_str("Ambiguous job");
-    logger.msg(Arc::ERROR, "Ambiguous job");
-               return NULL;
-       }
-       
-       Arc::Job& job = jobs_list.front();
-       
-       result = new_str(job.State().c_str());
-       
-       return result;
-       
-       
+  return NULL;
 }
 }
index 9224fb8..23243b8 100644 (file)
 
 #include "arc_libs.h"
 
 
 #include "arc_libs.h"
 
+#include "utils.h"
+
+static char* submit(const Arc::UserConfig& usercfg, const std::list<Arc::JobDescription>& jobdescriptionlist, std::list<Arc::Endpoint>& services, const std::string& requestedSubmissionInterface, const std::string& jobidfile, bool direct_submission);
+static int dumpjobdescription(const Arc::UserConfig& usercfg, const std::list<Arc::JobDescription>& jobdescriptionlist, const std::list<Arc::Endpoint>& services, const std::string& requestedSubmissionInterface);
 
 char* arc_submit(int argc, char **argv) {
 
 char* arc_submit(int argc, char **argv) {
-       
-       
-  char* job_id = NULL;
-       
-       
-
-       //TODO: what necessary here?
-       Arc::OptionParser options(istring("[filename ...]"),
-                                                         istring("The arcsub command is used for "
-                                                                         "submitting jobs to grid enabled "
-                                                                         "computing\nresources."),
-                                                         istring("Argument to -i has the format "
-                                                                         "Flavour:URL e.g.\n"
-                                                                         "ARC0:ldap://grid.tsl.uu.se:2135/"
-                                                                         "mds-vo-name=sweden,O=grid\n"
-                                                                         "CREAM:ldap://cream.grid.upjs.sk:2170/"
-                                                                         "o=grid\n"
-                                                                         "\n"
-                                                                         "Argument to -c has the format "
-                                                                         "Flavour:URL e.g.\n"
-                                                                         "ARC0:ldap://grid.tsl.uu.se:2135/"
-                                                                         "nordugrid-cluster-name=grid.tsl.uu.se,"
-                                                                         "Mds-Vo-name=local,o=grid"));
-       
-       std::list<std::string> clusters;
-       options.AddOption('c', "cluster",
-                                         istring("explicity select or reject a specific cluster"),
-                                         istring("[-]name"),
-                                         clusters);
-       
-       std::list<std::string> indexurls;
-       options.AddOption('i', "index",
-                                         istring("explicity select or reject an index server"),
-                                         istring("[-]name"),
-                                         indexurls);
-       
-       std::string jobdescriptionstring;
-       options.AddOption('e', "jobdescrstring",
-                                         istring("jobdescription string describing the job to "
-                                                         "be submitted"),
-                                         istring("string"),
-                                         jobdescriptionstring);
-       
-
-       
-       
-       //jt: dryrun was commented out in the original file, I try to use it TODO:
-     bool dryrun = false;
-     options.AddOption('D', "dryrun", istring("add dryrun option"),
-        dryrun);
-        
-       std::string joblist;
-       options.AddOption('j', "joblist",
-                                         istring("file where the jobs will be stored"),
-                                         istring("filename"),
-                                         joblist);
-       
-       
-       int timeout = -1;
-       options.AddOption('t', "timeout", istring("timeout in seconds (default 20)"),
-                                         istring("seconds"), timeout);
-       
-       std::string conffile;
-       options.AddOption('z', "conffile",
-                                         istring("configuration file (default ~/.arc/client.conf)"),
-                                         istring("filename"), conffile);
-               
-       std::string broker;
-       options.AddOption('b', "broker",
-                                         istring("select broker method (Random (default), FastestQueue, or custom)"),
-                                         istring("broker"), broker);
-       
-       
-       std::list<std::string> params = options.Parse(argc, argv);
-       
-       
-       Arc::UserConfig usercfg(conffile, joblist);
-       if (!usercfg) {
-               logger.msg(Arc::ERROR, "Failed configuration initialization");
-               return NULL;    
-       }
-       
-       if (timeout > 0)
-               usercfg.Timeout(timeout);
-       
-       if (!broker.empty())
-               usercfg.Broker(broker);
-               
-       if (!clusters.empty() || !indexurls.empty())
-               usercfg.ClearSelectedServices();
-       
-       if (!clusters.empty())
-               usercfg.AddServices(clusters, Arc::COMPUTING);
-       
-       if (!indexurls.empty())
-               usercfg.AddServices(indexurls, Arc::INDEX);
-       
-       if (jobdescriptionstring.empty()) {
-               logger.msg(Arc::ERROR, "No job description input specified");
-               return NULL;
-       }
-               
-       Arc::JobDescription jobdesc;
-       
-       jobdesc.Parse(jobdescriptionstring);
-       
-       if (!jobdesc){
-               
-               logger.msg(Arc::ERROR, "Invalid JobDescription");
-               return NULL;
-       }
-       
-       Arc::TargetGenerator targen(usercfg);
-       targen.RetrieveExecutionTargets();
+  Arc::ArcLocation::Init(argv[0]);
+
+  ClientOptions opt(ClientOptions::CO_SUB,
+                    istring("[filename ...]"),
+                    istring("The arcsub command is used for "
+                            "submitting jobs to Grid enabled "
+                            "computing\nresources."));
+
+  std::list<std::string> params = opt.Parse(argc, argv);
+
+  if (opt.showversion) {
+    std::cout << Arc::IString("%s version %s", "arcsub", "4.1.0")
+              << std::endl;
+    return 0;
+  }
+
+  // If debug is specified as argument, it should be set before loading the configuration.
+  if (!opt.debug.empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(opt.debug));
+
+  logger.msg(Arc::VERBOSE, "Running command: %s", opt.GetCommandWithArguments());
+
+  Arc::UserConfig usercfg(opt.conffile, opt.joblist);
+  if (!usercfg) {
+    logger.msg(Arc::ERROR, "Failed configuration initialization");
+    return NULL;
+  }
+
+  if (opt.show_plugins) {
+    std::list<std::string> types;
+    types.push_back("HED:SubmitterPlugin");
+    types.push_back("HED:ServiceEndpointRetrieverPlugin");
+    types.push_back("HED:TargetInformationRetrieverPlugin");
+    types.push_back("HED:JobDescriptionParserPlugin");
+    types.push_back("HED:BrokerPlugin");
+    showplugins("arcsub", types, logger, usercfg.Broker().first);
+    return 0;
+  }
+
+  if (!checkproxy(usercfg)) {
+    return NULL;
+  }
+
+  if (opt.debug.empty() && !usercfg.Verbosity().empty())
+    Arc::Logger::getRootLogger().setThreshold(Arc::istring_to_level(usercfg.Verbosity()));
+
+  if (opt.timeout > 0)
+    usercfg.Timeout(opt.timeout);
+
+  if (!opt.broker.empty())
+    usercfg.Broker(opt.broker);
+
+  opt.jobdescriptionfiles.insert(opt.jobdescriptionfiles.end(),
+                                 params.begin(), params.end());
+
+  if (opt.jobdescriptionfiles.empty() && opt.jobdescriptionstrings.empty()) {
+    logger.msg(Arc::ERROR, "No job description input specified");
+    return NULL;
+  }
+
+  std::list<Arc::JobDescription> jobdescriptionlist;
+
+  // Loop over input job description files
+  for (std::list<std::string>::iterator it = opt.jobdescriptionfiles.begin();
+       it != opt.jobdescriptionfiles.end(); it++) {
+
+    std::ifstream descriptionfile(it->c_str());
+
+    if (!descriptionfile) {
+      logger.msg(Arc::ERROR, "Can not open job description file: %s", *it);
+      return NULL;
+    }
+
+    descriptionfile.seekg(0, std::ios::end);
+    std::streamsize length = descriptionfile.tellg();
+    descriptionfile.seekg(0, std::ios::beg);
+
+    char *buffer = new char[length + 1];
+    descriptionfile.read(buffer, length);
+    descriptionfile.close();
+
+    buffer[length] = '\0';
+    std::list<Arc::JobDescription> jobdescs;
+    Arc::JobDescriptionResult parseres = Arc::JobDescription::Parse((std::string)buffer, jobdescs);
+    if (parseres) {
+      for (std::list<Arc::JobDescription>::iterator itJ = jobdescs.begin();
+           itJ != jobdescs.end(); itJ++) {
+        itJ->Application.DryRun = opt.dryrun;
+        for (std::list<Arc::JobDescription>::iterator itJAlt = itJ->GetAlternatives().begin();
+             itJAlt != itJ->GetAlternatives().end(); itJAlt++) {
+          itJAlt->Application.DryRun = opt.dryrun;
+        }
+      }
+
+      jobdescriptionlist.insert(jobdescriptionlist.end(), jobdescs.begin(), jobdescs.end());
+    }
+    else {
+      logger.msg(Arc::ERROR, "Invalid JobDescription:");
+      std::cout << buffer << std::endl;
+      delete[] buffer;
+      logger.msg(Arc::ERROR, "Parsing error:\n%s", parseres.str());
+      return NULL;
+    }
+    delete[] buffer;
+  }
+
+  //Loop over job description input strings
+  for (std::list<std::string>::iterator it = opt.jobdescriptionstrings.begin();
+       it != opt.jobdescriptionstrings.end(); it++) {
+
+    std::list<Arc::JobDescription> jobdescs;
+    if (Arc::JobDescription::Parse(*it, jobdescs)) {
+      for (std::list<Arc::JobDescription>::iterator itJ = jobdescs.begin();
+           itJ != jobdescs.end(); itJ++) {
+        itJ->Application.DryRun = opt.dryrun;
+        for (std::list<Arc::JobDescription>::iterator itJAlt = itJ->GetAlternatives().begin();
+             itJAlt != itJ->GetAlternatives().end(); itJAlt++) {
+          itJAlt->Application.DryRun = opt.dryrun;
+        }
+      }
+
+      jobdescriptionlist.insert(jobdescriptionlist.end(), jobdescs.begin(), jobdescs.end());
+    }
+    else {
+      logger.msg(Arc::ERROR, "Invalid JobDescription:");
+      std::cout << *it << std::endl;
+      return NULL;
+    }
+  }
+
+  std::list<Arc::Endpoint> services = getServicesFromUserConfigAndCommandLine(usercfg, opt.indexurls, opt.clusters, opt.requestedSubmissionInterfaceName, opt.infointerface);
+
+  if (!opt.direct_submission) {
+    usercfg.AddRejectDiscoveryURLs(opt.rejectdiscovery);
+  }
+
+  if (opt.dumpdescription) {
+    dumpjobdescription(usercfg, jobdescriptionlist, services, opt.requestedSubmissionInterfaceName);
+    return NULL;
+  }
+
+  return submit(usercfg, jobdescriptionlist, services, opt.requestedSubmissionInterfaceName, opt.jobidoutfile, opt.direct_submission);
+}
+
+class HandleSubmittedJobs : public Arc::EntityConsumer<Arc::Job> {
+public:
+  HandleSubmittedJobs(const std::string& jobidfile, const Arc::UserConfig& uc) : jobidfile(jobidfile), uc(uc), submittedJobs() {}
+
+  void addEntity(const Arc::Job& j) {
+    std::cout << Arc::IString("Job submitted with jobid: %s", j.JobID) << std::endl;
+    submittedJobs.push_back(j);
+  }
   
   
-       
-       if (targen.GetExecutionTargets().empty()) {
-               logger.msg(Arc::ERROR, "Job submission aborted because no clusters returned any information");
-               return NULL;
-       }
-       
-       
-       
-       Arc::BrokerLoader loader;
-       Arc::Broker *ChosenBroker = loader.load(usercfg.Broker().first, usercfg);
-       if (!ChosenBroker) {
-         logger.msg(Arc::ERROR, "Unable to load broker %s", usercfg.Broker().first);
-               return NULL;
-       }
-       logger.msg(Arc::INFO, "Broker %s loaded", usercfg.Broker().first);
-       
+  void write() const {
+    if (!jobidfile.empty() && !Arc::Job::WriteJobIDsToFile(submittedJobs, jobidfile)) {
+      logger.msg(Arc::WARNING, "Cannot write job IDs to file (%s)", jobidfile);
+    }
+    Arc::JobInformationStorage* jobStore = createJobInformationStorage(uc);
+    if (jobStore == NULL || !jobStore->Write(submittedJobs)) {
+      if (jobStore == NULL) {
+        std::cerr << Arc::IString("Warning: Unable to open job list file (%s), unknown format", uc.JobListFile()) << std::endl;
+      }
+      else {
+        std::cerr << Arc::IString("Warning: Failed to write job information to file (%s)", uc.JobListFile()) << std::endl;
+      }
+      std::cerr << "         " << Arc::IString("To recover missing jobs, run arcsync") << std::endl;
+    }
+    delete jobStore;
+  }
+
+  void printsummary(const std::list<Arc::JobDescription>& originalDescriptions, const std::list<const Arc::JobDescription*>& notsubmitted) const {
+    if (originalDescriptions.size() > 1) {
+      std::cout << std::endl << Arc::IString("Job submission summary:") << std::endl;
+      std::cout << "-----------------------" << std::endl;
+      std::cout << Arc::IString("%d of %d jobs were submitted", submittedJobs.size(), submittedJobs.size()+notsubmitted.size()) << std::endl;
+      if (!notsubmitted.empty()) {
+        std::cout << Arc::IString("The following %d were not submitted", notsubmitted.size()) << std::endl;
+        for (std::list<const Arc::JobDescription*>::const_iterator it = notsubmitted.begin();
+             it != notsubmitted.end(); ++it) {
+          int jobnr = 1;
+          for (std::list<Arc::JobDescription>::const_iterator itOrig = originalDescriptions.begin();
+               itOrig != originalDescriptions.end(); ++itOrig, ++jobnr) {
+            if (&(*itOrig) == *it) {
+              std::cout << Arc::IString("Job nr.") << " " << jobnr;
+              if (!(*it)->Identification.JobName.empty()) {
+                std::cout << ": " << (*it)->Identification.JobName;
+              }
+              std::cout << std::endl;
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  void clearsubmittedjobs() { submittedJobs.clear(); }
+
+  char* getJobID() {
+    return strdup(submittedJobs.back().JobID.c_str());
+  }
+
+private:
+  const std::string jobidfile;
+  const Arc::UserConfig& uc;
   std::list<Arc::Job> submittedJobs;
   std::list<Arc::Job> submittedJobs;
+};
+
+
+static char* submit(const Arc::UserConfig& usercfg, const std::list<Arc::JobDescription>& jobdescriptionlist, std::list<Arc::Endpoint>& services, const std::string& requestedSubmissionInterface, const std::string& jobidfile, bool direct_submission) {
+  int retval = 0;
   
   
-  submittedJobs.push_back(Arc::Job());  
+  HandleSubmittedJobs hsj(jobidfile, usercfg);
+  Arc::Submitter s(usercfg);
+  s.addConsumer(hsj);
 
 
-  if (ChosenBroker->Submit(targen.GetExecutionTargets(), jobdesc, submittedJobs.back())) {
-    job_id = new_str(submittedJobs.back().JobID.str().c_str());
-    logger.msg(Arc::DEBUG, "Job submitted with ID: %s", job_id);
-  } else {
-    logger.msg(Arc::ERROR, "Job submission failed (ChosenBroker->Submit returned false)");
-    submittedJobs.pop_back();
+  Arc::SubmissionStatus status;
+  if (!direct_submission) {
+    std::list<std::string> rsi;
+    if (!requestedSubmissionInterface.empty()) rsi.push_back(requestedSubmissionInterface);
+    status = s.BrokeredSubmit(services, jobdescriptionlist, rsi);
+  }
+  else {
+    if (!requestedSubmissionInterface.empty()) {
+      for (std::list<Arc::Endpoint>::iterator it = services.begin(); it != services.end();) {
+        // Remove endpoint - it has an unrequested interface name.
+        if (!it->InterfaceName.empty() && it->InterfaceName != requestedSubmissionInterface) {
+          logger.msg(Arc::INFO, "Removing endpoint %s: It has an unrequested interface (%s).", it->URLString, it->InterfaceName);
+          it = services.erase(it);
+          continue;
+        }
+        
+        it->InterfaceName = requestedSubmissionInterface;
+        ++it;
+      }
+    }
+    status = s.Submit(services, jobdescriptionlist);
+  }
+  hsj.write();
+
+  if (status.isSet(Arc::SubmissionStatus::BROKER_PLUGIN_NOT_LOADED)) {
+    std::cerr << Arc::IString("ERROR: Unable to load broker %s", usercfg.Broker().first) << std::endl;
+    return NULL;
+  }
+  if (status.isSet(Arc::SubmissionStatus::NO_SERVICES)) {
+   std::cerr << Arc::IString("ERROR: Job submission aborted because no resource returned any information") << std::endl;
+   return NULL;
+  }
+  if (status.isSet(Arc::SubmissionStatus::DESCRIPTION_NOT_SUBMITTED)) {
+    std::cerr << Arc::IString("ERROR: One or multiple job descriptions was not submitted.") << std::endl;
+    retval = 1;
+  }
+  if (status.isSet(Arc::SubmissionStatus::SUBMITTER_PLUGIN_NOT_LOADED)) {
+    bool gridFTPJobPluginFailed = false;
+    for (std::map<Arc::Endpoint, Arc::EndpointSubmissionStatus>::const_iterator it = s.GetEndpointSubmissionStatuses().begin();
+         it != s.GetEndpointSubmissionStatuses().end(); ++it) {
+      if (it->first.InterfaceName == "org.nordugrid.gridftpjob" && it->second == Arc::EndpointSubmissionStatus::NOPLUGIN) {
+        gridFTPJobPluginFailed = true;
+      }
+    }
+    if (gridFTPJobPluginFailed) {
+      Arc::LogLevel level  = (retval == 1 ? Arc::ERROR : Arc::INFO);
+      std::string indent   = (retval == 1 ? "       " : "      ");
+      logger.msg(level, "A computing resource using the GridFTP interface was requested, but\n"
+                        "%sthe corresponding plugin could not be loaded. Is the plugin installed?\n"
+                        "%sIf not, please install the package 'nordugrid-arc-plugins-globus'.\n"
+                        "%sDepending on your type of installation the package name might differ.", indent, indent, indent);
+    }
+    // TODO: What to do when failing to load other plugins.
   }
   }
-  
-  Arc::Job::WriteJobsToFile(usercfg.JobListFile(), submittedJobs);
     
     
-  return job_id;
+  hsj.printsummary(jobdescriptionlist, s.GetDescriptionsNotSubmitted());
+
+  if (retval == 0) {
+    return hsj.getJobID();
+  }
+  return NULL;
 }
 
 }
 
+static int dumpjobdescription(const Arc::UserConfig& usercfg, const std::list<Arc::JobDescription>& jobdescriptionlist, const std::list<Arc::Endpoint>& services, const std::string& requestedSubmissionInterface) {
+  int retval = 0;
+
+  std::set<std::string> preferredInterfaceNames;
+  if (usercfg.InfoInterface().empty()) {
+    preferredInterfaceNames.insert("org.nordugrid.ldapglue2");
+  } else {
+    preferredInterfaceNames.insert(usercfg.InfoInterface());
+  }
+
+  Arc::ComputingServiceUniq csu;
+  Arc::ComputingServiceRetriever csr(usercfg, std::list<Arc::Endpoint>(), usercfg.RejectDiscoveryURLs(), preferredInterfaceNames);
+  csr.addConsumer(csu);
+  for (std::list<Arc::Endpoint>::const_iterator it = services.begin(); it != services.end(); it++) {
+    csr.addEndpoint(*it);
+  }
+  csr.wait();
+  std::list<Arc::ComputingServiceType> CEs = csu.getServices();
+
+
+  if (CEs.empty()) {
+    std::cout << Arc::IString("Unable to adapt job description to any resource, no resource information could be obtained.") << std::endl;
+    std::cout << Arc::IString("Original job description is listed below:") << std::endl;
+    for (std::list<Arc::JobDescription>::const_iterator it = jobdescriptionlist.begin();
+         it != jobdescriptionlist.end(); ++it) {
+      std::string descOutput;
+      it->UnParse(descOutput, it->GetSourceLanguage());
+      std::cout << descOutput << std::endl;
+    }
+    return 1;
+  }
+
+  Arc::Broker broker(usercfg, usercfg.Broker().first);
+  if (!broker.isValid(false)) {
+    logger.msg(Arc::ERROR, "Dumping job description aborted: Unable to load broker %s", usercfg.Broker().first);
+    return 1;
+  }
+
+  Arc::ExecutionTargetSorter ets(broker, CEs);
+  std::list<Arc::JobDescription>::const_iterator itJAlt; // Iterator to use for alternative job descriptions.
+  for (std::list<Arc::JobDescription>::const_iterator itJ = jobdescriptionlist.begin();
+       itJ != jobdescriptionlist.end(); ++itJ) {
+    const Arc::JobDescription* currentJobDesc = &*itJ;
+    bool descriptionDumped = false;
+    do {
+      Arc::JobDescription jobdescdump(*currentJobDesc);
+      ets.set(jobdescdump);
+
+      for (ets.reset(); !ets.endOfList(); ets.next()) {
+        if(!requestedSubmissionInterface.empty() && ets->ComputingEndpoint->InterfaceName != requestedSubmissionInterface) continue;
+        if (!jobdescdump.Prepare(*ets)) {
+          logger.msg(Arc::INFO, "Unable to prepare job description according to needs of the target resource (%s).", ets->ComputingEndpoint->URLString); 
+          continue;
+        }
+  
+        std::string jobdesclang = "nordugrid:jsdl";
+        if (ets->ComputingEndpoint->InterfaceName == "org.nordugrid.gridftpjob") {
+          jobdesclang = "nordugrid:xrsl";
+        }
+        else if (ets->ComputingEndpoint->InterfaceName == "org.glite.ce.cream") {
+          jobdesclang = "egee:jdl";
+        }
+        else if (ets->ComputingEndpoint->InterfaceName == "org.ogf.glue.emies.activitycreation") {
+          jobdesclang = "emies:adl";
+        }
+        std::string jobdesc;
+        if (!jobdescdump.UnParse(jobdesc, jobdesclang)) {
+          logger.msg(Arc::INFO, "An error occurred during the generation of job description to be sent to %s", ets->ComputingEndpoint->URLString); 
+          continue;
+        }
+  
+        std::cout << Arc::IString("Job description to be sent to %s:", ets->AdminDomain->Name) << std::endl;
+        std::cout << jobdesc << std::endl;
+        descriptionDumped = true;
+        break;
+      }
+
+      if (!descriptionDumped && itJ->HasAlternatives()) { // Alternative job descriptions.
+        if (currentJobDesc == &*itJ) {
+          itJAlt = itJ->GetAlternatives().begin();
+        }
+        else {
+          ++itJAlt;
+        }
+        currentJobDesc = &*itJAlt;
+      }
+    } while (!descriptionDumped && itJ->HasAlternatives() && itJAlt != itJ->GetAlternatives().end());
+
+    if (ets.endOfList()) {
+      std::cout << Arc::IString("Unable to prepare job description according to needs of the target resource.") << std::endl;
+      retval = 1;
+    }
+  } //end loop over all job descriptions
+
+  return retval;
+}
 
 
index ebcfde7..3746693 100644 (file)
@@ -1,6 +1,7 @@
 require 'mkmf'
 
 dirs = <<-EODIRS
 require 'mkmf'
 
 dirs = <<-EODIRS
+/usr/include/c++/4.7/bits
 /usr/local/include/libxml2 
 /usr/local/include/giomm-2.4 
 /usr/local/lib/giomm-2.4/include 
 /usr/local/include/libxml2 
 /usr/local/include/giomm-2.4 
 /usr/local/lib/giomm-2.4/include 
@@ -11,6 +12,7 @@ dirs = <<-EODIRS
 /usr/local/include 
 /usr/local/include/sigc++-2.0 
 /usr/local/lib/sigc++-2.0/include
 /usr/local/include 
 /usr/local/include/sigc++-2.0 
 /usr/local/lib/sigc++-2.0/include
+/usr/include
 EODIRS
 
 dirs.split.each do |dir|
 EODIRS
 
 dirs.split.each do |dir|
@@ -29,7 +31,8 @@ end
 #for debug info
 $CFLAGS << '-g'
 
 #for debug info
 $CFLAGS << '-g'
 
-$LIBS << ' -larcclient -larccommon -larcdata2 -larcloader -larcmessage -lglibmm-2.4 -lsigc-2.0'
+#$LIBS << ' -larcclient -larccommon -larcdata2 -larcloader -larcmessage -lglibmm-2.4 -lsigc-2.0'
+$LIBS << ' -larccompute -larccommon -larcdata -larcloader -larcmessage -lglibmm-2.4 -lsigc-2.0'
 
 create_makefile("arc_client_c")
 
 
 create_makefile("arc_client_c")
 
diff --git a/ext/utils.cpp b/ext/utils.cpp
new file mode 100644 (file)
index 0000000..d589ca7
--- /dev/null
@@ -0,0 +1,511 @@
+// -*- indent-tabs-mode: nil -*-
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glibmm.h>
+
+#include <arc/ArcConfig.h>
+#include <arc/IString.h>
+#include <arc/credential/Credential.h>
+#include <arc/loader/FinderLoader.h>
+#include <arc/loader/Plugin.h>
+
+#include "utils.h"
+
+std::list<std::string> getSelectedURLsFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> computingelements) {
+  std::list<Arc::Endpoint> endpoints = getServicesFromUserConfigAndCommandLine(usercfg, std::list<std::string>(), computingelements);
+  std::list<std::string> serviceURLs;
+  for (std::list<Arc::Endpoint>::const_iterator it = endpoints.begin(); it != endpoints.end(); it++) {
+    serviceURLs.push_back(it->URLString);
+  }
+  return serviceURLs;
+}
+
+std::list<std::string> getRejectDiscoveryURLsFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> rejectdiscovery) {
+  std::list<std::string> rejectDiscoveryURLs = usercfg.RejectDiscoveryURLs();  
+  rejectDiscoveryURLs.insert(rejectDiscoveryURLs.end(), rejectdiscovery.begin(), rejectdiscovery.end());
+  return rejectDiscoveryURLs;
+}
+
+std::list<std::string> getRejectManagementURLsFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> rejectmanagement) {
+  std::list<std::string> rejectManagementURLs = usercfg.RejectManagementURLs();  
+  rejectManagementURLs.insert(rejectManagementURLs.end(), rejectmanagement.begin(), rejectmanagement.end());
+  return rejectManagementURLs;
+}
+
+
+std::list<Arc::Endpoint> getServicesFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> registries, std::list<std::string> computingelements, std::string requestedSubmissionInterfaceName, std::string infointerface) {
+  std::list<Arc::Endpoint> services;
+  if (computingelements.empty() && registries.empty()) {
+    std::list<Arc::ConfigEndpoint> endpoints = usercfg.GetDefaultServices();
+    for (std::list<Arc::ConfigEndpoint>::const_iterator its = endpoints.begin(); its != endpoints.end(); its++) {
+      services.push_back(*its);
+    }
+  } else {
+    for (std::list<std::string>::const_iterator it = computingelements.begin(); it != computingelements.end(); it++) {
+      // check if the string is a group or alias
+      std::list<Arc::ConfigEndpoint> newServices = usercfg.GetServices(*it, Arc::ConfigEndpoint::COMPUTINGINFO);
+      if (newServices.empty()) {
+          // if it was not an alias or a group, then it should be the URL
+          Arc::Endpoint service(*it);
+          service.Capability.insert(Arc::Endpoint::GetStringForCapability(Arc::Endpoint::COMPUTINGINFO));
+          if (!infointerface.empty()) {
+            service.InterfaceName = infointerface;            
+          }
+          service.RequestedSubmissionInterfaceName = requestedSubmissionInterfaceName;
+          services.push_back(service);
+      } else {
+        // if it was a group (or an alias), add all the services
+        for (std::list<Arc::ConfigEndpoint>::iterator its = newServices.begin(); its != newServices.end(); its++) {
+          if (!requestedSubmissionInterfaceName.empty()) {
+            // if there was a submission interface requested, this overrides the one from the config
+            its->RequestedSubmissionInterfaceName = requestedSubmissionInterfaceName;    
+          }
+          services.push_back(*its);
+        }
+      }
+    }
+    for (std::list<std::string>::const_iterator it = registries.begin(); it != registries.end(); it++) {
+      // check if the string is a name of a group
+      std::list<Arc::ConfigEndpoint> newServices = usercfg.GetServices(*it, Arc::ConfigEndpoint::REGISTRY);
+      if (newServices.empty()) {
+          // if it was not an alias or a group, then it should be the URL
+          Arc::Endpoint service(*it);
+          service.Capability.insert(Arc::Endpoint::GetStringForCapability(Arc::Endpoint::REGISTRY));
+          services.push_back(service);
+      } else {
+        // if it was a group (or an alias), add all the services
+        services.insert(services.end(), newServices.begin(), newServices.end());
+      }
+    }
+  }
+  return services;
+}
+
+
+void showplugins(const std::string& program, const std::list<std::string>& types, Arc::Logger& logger, const std::string& chosenBroker) {
+
+  for (std::list<std::string>::const_iterator itType = types.begin();
+       itType != types.end(); ++itType) {
+    if (*itType == "HED:SubmitterPlugin") {
+      std::cout << Arc::IString("Types of execution services %s is able to submit jobs to:", program) << std::endl;
+    }
+    else if (*itType == "HED:ServiceEndpointRetrieverPlugin") {
+      std::cout << Arc::IString("Types of registry services which %s is able collect information from:", program) << std::endl;
+    }
+    else if (*itType == "HED:TargetInformationRetrieverPlugin") {
+      std::cout << Arc::IString("Types of local information services which %s is able collect information from:", program) << std::endl;
+    }
+    else if (*itType == "HED:JobListRetriever") {
+      std::cout << Arc::IString("Types of local information services which %s is able collect job information from:", program) << std::endl;
+    }
+    else if (*itType == "HED:JobControllerPlugin") {
+      std::cout << Arc::IString("Types of services %s is able to manage jobs at:", program) << std::endl;
+    }
+    else if (*itType == "HED:JobDescriptionParserPlugin") {
+      std::cout << Arc::IString("Job description languages supported by %s:", program) << std::endl;
+    }
+    else if (*itType == "HED:BrokerPlugin") {
+      std::cout << Arc::IString("Brokers available to %s:", program) << std::endl;
+    }
+
+    std::list<Arc::ModuleDesc> modules;
+    Arc::PluginsFactory pf(Arc::BaseConfig().MakeConfig(Arc::Config()).Parent());
+
+    bool isDefaultBrokerLocated = false;
+    pf.scan(Arc::FinderLoader::GetLibrariesList(), modules);
+    Arc::PluginsFactory::FilterByKind(*itType, modules);
+    for (std::list<Arc::ModuleDesc>::iterator itMod = modules.begin();
+         itMod != modules.end(); itMod++) {
+      for (std::list<Arc::PluginDesc>::iterator itPlug = itMod->plugins.begin();
+           itPlug != itMod->plugins.end(); itPlug++) {
+        std::cout << "  " << itPlug->name;
+        if (*itType == "HED:BrokerPlugin" && itPlug->name == chosenBroker) {
+          std::cout << " (default)";
+          isDefaultBrokerLocated = true;
+        }
+        std::cout << " - " << itPlug->description << std::endl;
+      }
+    }
+
+    if (*itType == "HED:BrokerPlugin" && !isDefaultBrokerLocated) {
+      logger.msg(Arc::WARNING, "Default broker (%s) is not available. When using %s a broker should be specified explicitly (-b option).", chosenBroker, program);
+    }
+  }
+}
+
+bool checkproxy(const Arc::UserConfig& uc)
+{
+  if (!uc.ProxyPath().empty() ) {
+    Arc::Credential holder(uc.ProxyPath(), "", "", "");
+    if (holder.GetEndTime() < Arc::Time()){
+      std::cout << Arc::IString("Proxy expired. Job submission aborted. Please run 'arcproxy'!") << std::endl;
+      return false;
+    }
+  }
+  else {
+    std::cout << Arc::IString("Cannot find any proxy. This application currently cannot run without a proxy.\n"
+                              "  If you have the proxy file in a non-default location,\n"
+                              "  please make sure the path is specified in the client configuration file.\n"
+                              "  If you don't have a proxy yet, please run 'arcproxy'!") << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+void splitendpoints(std::list<std::string>& selected, std::list<std::string>& rejected)
+{
+  // Removes slashes from end of endpoint strings, and put strings with leading '-' into rejected list.
+  for (std::list<std::string>::iterator it = selected.begin();
+       it != selected.end();) {
+    if ((*it)[it->length()-1] == '/') {
+      it->erase(it->length()-1);
+      continue;
+    }
+    if (it->empty()) {
+      it = selected.erase(it);
+      continue;
+    }
+
+    if ((*it)[0] == '-') {
+      rejected.push_back(it->substr(1));
+      it = selected.erase(it);
+    }
+    else {
+      ++it;
+    }
+  }
+}
+
+Arc::JobInformationStorage* createJobInformationStorage(const Arc::UserConfig& uc) {
+  Arc::JobInformationStorage* jis = NULL;
+  if (Glib::file_test(uc.JobListFile(), Glib::FILE_TEST_EXISTS)) {
+    for (int i = 0; Arc::JobInformationStorage::AVAILABLE_TYPES[i].name != NULL; ++i) {
+      jis = (Arc::JobInformationStorage::AVAILABLE_TYPES[i].instance)(uc.JobListFile());
+      if (jis && jis->IsValid()) {
+        return jis;
+      }
+      delete jis;
+    }
+    return NULL;
+  }
+  
+  for (int i = 0; Arc::JobInformationStorage::AVAILABLE_TYPES[i].name != NULL; ++i) {
+    if (uc.JobListType() == Arc::JobInformationStorage::AVAILABLE_TYPES[i].name) {
+      jis = (Arc::JobInformationStorage::AVAILABLE_TYPES[i].instance)(uc.JobListFile());
+      if (jis && jis->IsValid()) {
+        return jis;
+      }
+      delete jis;
+      return NULL;
+    }
+  }
+
+  if (Arc::JobInformationStorage::AVAILABLE_TYPES[0].instance != NULL) {
+    jis = (Arc::JobInformationStorage::AVAILABLE_TYPES[0].instance)(uc.JobListFile());
+    if (jis && jis->IsValid()) {
+      return jis;
+    }
+    delete jis;
+  }
+  
+  return NULL;
+}
+
+
+ClientOptions::ClientOptions(Client_t c,
+                             const std::string& arguments,
+                             const std::string& summary,
+                             const std::string& description) :
+    Arc::OptionParser(arguments, summary, description),
+    dryrun(false),
+    dumpdescription(false),
+    show_credentials(false),
+    show_plugins(false),
+    showversion(false),
+    all(false),
+    forcemigration(false),
+    keep(false),
+    forcesync(false),
+    truncate(false),
+    longlist(false),
+    printids(false),
+    same(false),
+    notsame(false),
+    show_stdout(true),
+    show_stderr(false),
+    show_joblog(false),
+    usejobname(false),
+    forcedownload(false),
+    list_configured_services(false),
+    direct_submission(false),
+    show_unavailable(false),
+    testjobid(-1),
+    runtime(5),
+    timeout(-1)
+{
+  bool cIsJobMan = (c == CO_CAT || c == CO_CLEAN || c == CO_GET || c == CO_KILL || c == CO_RENEW || c == CO_RESUME || c == CO_STAT || c == CO_ACL);
+
+  AddOption('c', "cluster",
+            istring("select one or more computing elements: "
+                    "name can be an alias for a single CE, a group of CEs or a URL"),
+            istring("name"),
+            clusters);
+  
+  if (!cIsJobMan && c != CO_SYNC) {
+    AddOption('I', "infointerface",
+              istring("the computing element specified by URL at the command line "
+                      "should be queried using this information interface "
+                      "(possible options: org.nordugrid.ldapng, org.nordugrid.ldapglue2, "
+                      "org.nordugrid.wsrfglue2, org.ogf.glue.emies.resourceinfo)"),
+              istring("interfacename"),
+              infointerface);
+  }
+
+  if (c == CO_RESUB || c == CO_MIGRATE) {
+    AddOption('q', "qluster",
+              istring("selecting a computing element for the new jobs with a URL or an alias, "
+                      "or selecting a group of computing elements with the name of the group"),
+              istring("name"),
+              qlusters);
+  }
+
+  if (c == CO_MIGRATE) {
+    AddOption('f', "force",
+              istring("force migration, ignore kill failure"),
+              forcemigration);
+  }
+
+  if (c == CO_GET || c == CO_KILL || c == CO_MIGRATE || c == CO_RESUB) {
+    AddOption('k', "keep",
+              istring("keep the files on the server (do not clean)"),
+              keep);
+  }
+
+  if (c == CO_SYNC) {
+    AddOption('f', "force",
+              istring("do not ask for verification"),
+              forcesync);
+
+    AddOption('T', "truncate",
+              istring("truncate the joblist before synchronizing"),
+              truncate);
+  }
+
+  if (c == CO_INFO || c == CO_STAT) {
+    AddOption('l', "long",
+              istring("long format (more information)"),
+              longlist);
+  }
+
+  if (c == CO_INFO) {
+    AddOption('L', "list-configured-services",
+              istring("print a list of services configured in the client.conf"),
+              list_configured_services);
+  }
+
+  if (c == CO_CAT) {
+    AddOption('o', "stdout",
+              istring("show the stdout of the job (default)"),
+              show_stdout);
+
+    AddOption('e', "stderr",
+              istring("show the stderr of the job"),
+              show_stderr);
+
+    AddOption('l', "joblog",
+              istring("show the CE's error log of the job"),
+              show_joblog);
+  }
+
+  if (c == CO_GET) {
+    AddOption('D', "dir",
+              istring("download directory (the job directory will"
+                      " be created in this directory)"),
+              istring("dirname"),
+              downloaddir);
+
+    AddOption('J', "usejobname",
+              istring("use the jobname instead of the short ID as"
+                      " the job directory name"),
+              usejobname);
+
+    AddOption('f', "force",
+              istring("force download (overwrite existing job directory)"),
+              forcedownload);
+  }
+
+  if (c == CO_STAT) {
+    // Option 'long' takes precedence over this option (print-jobids).
+    AddOption('p', "print-jobids", istring("instead of the status only the IDs of "
+              "the selected jobs will be printed"), printids);
+
+    AddOption('S', "sort",
+              istring("sort jobs according to jobid, submissiontime or jobname"),
+              istring("order"), sort);
+    AddOption('R', "rsort",
+              istring("reverse sorting of jobs according to jobid, submissiontime or jobname"),
+              istring("order"), rsort);
+
+    AddOption('u', "show-unavailable",
+              istring("show jobs where status information is unavailable"),
+              show_unavailable);
+  }
+
+  if (c == CO_RESUB) {
+    AddOption('m', "same",
+              istring("resubmit to the same resource"),
+              same);
+
+    AddOption('M', "not-same",
+              istring("do not resubmit to the same resource"),
+              notsame);
+  }
+
+  if (c == CO_CLEAN) {
+    AddOption('f', "force",
+              istring("remove the job from the local list of jobs "
+                      "even if the job is not found in the infosys"),
+              forceclean);
+  }
+
+  if (!cIsJobMan) {
+    AddOption('g', "index",
+              istring("select one or more registries: "
+                      "name can be an alias for a single registry, a group of registries or a URL"),
+              istring("name"),
+              indexurls);
+  }
+
+  if (c == CO_TEST) {
+    AddOption('J', "job",
+              istring("submit test job given by the number"),
+              istring("int"),
+              testjobid);
+    AddOption('r', "runtime",
+              istring("test job runtime specified by the number"),
+              istring("int"),
+              runtime);
+  }
+
+  if (cIsJobMan || c == CO_RESUB) {
+    AddOption('s', "status",
+              istring("only select jobs whose status is statusstr"),
+              istring("statusstr"),
+              status);
+  }
+
+  if (cIsJobMan || c == CO_MIGRATE || c == CO_RESUB) {
+    AddOption('a', "all",
+              istring("all jobs"),
+              all);
+  }
+
+  if (c == CO_SUB) {
+    AddOption('e', "jobdescrstring",
+              istring("jobdescription string describing the job to "
+                      "be submitted"),
+              istring("string"),
+              jobdescriptionstrings);
+
+    AddOption('f', "jobdescrfile",
+              istring("jobdescription file describing the job to "
+                      "be submitted"),
+              istring("string"),
+              jobdescriptionfiles);
+  }
+
+  if (c == CO_MIGRATE || c == CO_RESUB || c == CO_SUB || c == CO_TEST) {
+    AddOption('b', "broker",
+              istring("select broker method (list available brokers with --listplugins flag)"),
+              istring("broker"), broker);
+
+    AddOption('o', "jobids-to-file",
+              istring("the IDs of the submitted jobs will be appended to this file"),
+              istring("filename"),
+              jobidoutfile);
+    
+    AddOption('S', "submissioninterface",
+              istring("only use this interface for submitting "
+                      "(e.g. org.nordugrid.gridftpjob, org.ogf.glue.emies.activitycreation, org.ogf.bes)"),
+              istring("InterfaceName"),
+              requestedSubmissionInterfaceName);
+
+  }
+  
+  if (c == CO_MIGRATE || c == CO_RESUB || c == CO_SUB || c == CO_TEST || c == CO_INFO) {
+    AddOption('R', "rejectdiscovery",
+              istring("skip the service with the given URL during service discovery"),
+              istring("URL"),
+              rejectdiscovery);
+  }
+  
+
+  if (cIsJobMan || c == CO_MIGRATE || c == CO_RESUB) {
+    AddOption('i', "jobids-from-file",
+              istring("a file containing a list of jobIDs"),
+              istring("filename"),
+              jobidinfiles);
+
+    AddOption('r', "rejectmanagement",
+              istring("skip jobs which are on a computing element with a given URL"),
+              istring("URL"),
+              rejectmanagement);    
+  }
+
+  if (c == CO_SUB || c == CO_TEST) {
+    AddOption('D', "dryrun", istring("submit jobs as dry run (no submission to batch system)"),
+              dryrun);
+
+    AddOption(0, "direct", istring("submit directly - no resource discovery or matchmaking"),
+              direct_submission);
+
+    AddOption('x', "dumpdescription",
+              istring("do not submit - dump job description "
+                      "in the language accepted by the target"),
+              dumpdescription);
+  }
+  
+  if (c == CO_INFO) {
+    AddOption('S', "submissioninterface",
+              istring("only get information about executon targets which support this job submission interface "
+                      "(e.g. org.nordugrid.gridftpjob, org.ogf.glue.emies.activitycreation, org.ogf.bes)"),
+              istring("InterfaceName"),
+              requestedSubmissionInterfaceName);
+  }
+
+  if (c == CO_TEST) {
+    AddOption('E', "certificate", istring("prints info about installed user- and CA-certificates"), show_credentials);
+  }
+
+  if (c != CO_INFO) {
+    AddOption('j', "joblist",
+              Arc::IString("the file storing information about active jobs (default %s)", Arc::UserConfig::JOBLISTFILE).str(),
+              istring("filename"),
+              joblist);
+  }
+
+  /* --- Standard options below --- */
+
+  AddOption('z', "conffile",
+            istring("configuration file (default ~/.arc/client.conf)"),
+            istring("filename"), conffile);
+
+  AddOption('t', "timeout", istring("timeout in seconds (default 20)"),
+            istring("seconds"), timeout);
+
+  AddOption('P', "listplugins",
+            istring("list the available plugins"),
+            show_plugins);
+
+  AddOption('d', "debug",
+            istring("FATAL, ERROR, WARNING, INFO, VERBOSE or DEBUG"),
+            istring("debuglevel"), debug);
+
+  AddOption('v', "version", istring("print version information"),
+            showversion);
+
+}
diff --git a/ext/utils.h b/ext/utils.h
new file mode 100644 (file)
index 0000000..a930d72
--- /dev/null
@@ -0,0 +1,164 @@
+#include <unistd.h>
+#include <string>
+#include <list>
+#include <arc/Logger.h>
+#include <arc/UserConfig.h>
+#include <arc/OptionParser.h>
+#include <arc/compute/Endpoint.h>
+#include <arc/compute/Job.h>
+#include <arc/compute/JobInformationStorage.h>
+
+#ifdef TEST
+#define RUNMAIN(X) test_##X##_main
+#else
+#define RUNMAIN(X) X(int argc, char **argv); \
+  int main(int argc, char **argv) { _exit(X(argc,argv)); return 0; } \
+  int X
+#endif
+
+/// Returns the URLs of computing elements selected by alias, group name, URL or the default ones
+/**
+  This helper method gets a list of string representing computing elements. Each item of the list
+  is either an alias of service configured in the UserConfig, a name of a group configured in the
+  UserConfig, or a URL of service not configured in the UserConfig. If the list is empty, the
+  default services will be selected from the UserConfig. The method returns the URLs of the
+  selected services.
+  
+  This is meant to be used by the command line programs where the user is specifying
+  a list of computing elements by alias, group name (which has to be looked up in the UserConfig),
+  or by URL.
+  \param[in] usercfg is the UserConfig object containing information about configured services
+  \param[in] computingelements is a list of strings containing aliases, group names, or URLs of computing elements
+  \return a list of URL strings, the endpoints of the selected services, or the default ones if none was selected
+*/
+std::list<std::string> getSelectedURLsFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> computingelements);
+
+/// Combine the list of rejected discovery URLs from the UserConfig with the ones specified in a list
+/**
+  Helper method for the command line programs to combine the list of rejected discovery URLs
+  specified by the user at the command line with the ones configured in the UserConfig.
+  
+  The rejected discovery URLs supposed to cause the service discovery not to discovery computing elements
+  whose URL matches any of these strings.
+  
+  \param[in] usercfg is the UserConfig object containing information about configured services
+  \param[in] rejectdiscovery is a list of strings, which will be also added
+    to the resulting list besides the ones from the UserConfig
+  \return a list of strings which are the rejected URLs from the UserConfig and
+    the ones given as the second argument combined
+*/
+std::list<std::string> getRejectDiscoveryURLsFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> rejectdiscovery);
+
+/// Combine the list of rejected management URLs from the UserConfig with the ones specified in a list
+/**
+  Helper method for the command line programs to combine the list of rejected management URLs
+  specified by the user at the command line with the ones configured in the UserConfig.
+  
+  The rejected management URLs supposed to cause the job management commands not to manage
+  jobs which reside on computing elements whose URL matches any of the items in the list
+  
+  \param[in] usercfg is the UserConfig object containing information about configured services
+  \param[in] rejectmanagement is a list of strings, which will be also added
+    to the resulting list besides the ones from the UserConfig
+  \return a list of strings which are the rejected URLs from the UserConfig and
+    the ones given as the second argument combined
+*/
+std::list<std::string> getRejectManagementURLsFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> rejectmanagement);
+
+/// Looks up or creates Endpoints from strings specified at the command line using the information from the UserConfig
+/**
+  This helper method gets a list of strings representing service registries and computing element,
+  along with a requested submisison interface, looks up all the services from the UserConfig,
+  and return the Endpoints found there, or create new Endpoints for services not found in the Userconfig.
+  If there are no registries or computing elements given, then the default services will be returned.
+  
+  This is meant to be used by the command line programs where the user is specifying service registries
+  and/or computing elements with several strings, which could refer to services configured in the
+  UserConfig (aliases or groups), or they can be URLs refering to services which are not configured in
+  the UserConfig. This method looks up the aliases and group names, and if a string is not an alias or
+  a group name, then it's assumed to be a URL.
+  
+  \param[in] usercfg is the UserConfig object containing information about configured services
+  \param[in] registries is a list of strings containing aliases, group names, or URLs of service registries
+  \param[in] computingelements is a list of strings containing aliases, group names, or URLs of computing elements
+  \return a list of Endpoint objects containing the services corresponding the given strings or the default services.
+*/
+std::list<Arc::Endpoint> getServicesFromUserConfigAndCommandLine(Arc::UserConfig usercfg, std::list<std::string> registries, std::list<std::string> computingelements, std::string requestedSubmissionInterfaceName = "", std::string infointerface = "");
+
+void showplugins(const std::string& program, const std::list<std::string>& types, Arc::Logger& logger, const std::string& chosenBroker = "");
+
+bool checkproxy(const Arc::UserConfig& uc);
+
+void splitendpoints(std::list<std::string>& selected, std::list<std::string>& rejected);
+
+/**
+ * Creates a new JobInformationStorage object. Caller has responsibility of
+ * deleting returned object.
+ */
+Arc::JobInformationStorage* createJobInformationStorage(const Arc::UserConfig& uc);
+
+class ClientOptions : public Arc::OptionParser {
+public:
+  enum Client_t {
+    CO_SUB, CO_MIGRATE, CO_RESUB, CO_TEST,
+    CO_CAT, CO_CLEAN, CO_GET, CO_KILL, CO_RENEW, CO_RESUME, CO_STAT,
+    CO_SYNC,
+    CO_INFO,
+    CO_ACL
+ };
+
+  ClientOptions(Client_t c,
+                const std::string& arguments = "",
+                const std::string& summary = "",
+                const std::string& description = "");
+
+  bool dryrun;
+  bool dumpdescription;
+  bool show_credentials;
+  bool show_plugins;
+  bool showversion;
+  bool all;
+  bool forcemigration;
+  bool keep;
+  bool forcesync;
+  bool truncate;
+  bool longlist;
+  bool printids;
+  bool same;
+  bool notsame;
+  bool forceclean;
+  bool show_stdout;
+  bool show_stderr;
+  bool show_joblog;
+  bool usejobname;
+  bool forcedownload;
+  bool list_configured_services;
+  bool direct_submission;
+  bool show_unavailable;
+
+  int testjobid;
+  int runtime;
+  int timeout;
+
+  std::string joblist;
+  std::string jobidoutfile;
+  std::string conffile;
+  std::string debug;
+  std::string broker;
+  std::string sort;
+  std::string rsort;
+  std::string downloaddir;
+  std::string requestedSubmissionInterfaceName;
+  std::string infointerface;
+
+  std::list<std::string> clusters;
+  std::list<std::string> qlusters;
+  std::list<std::string> indexurls;
+  std::list<std::string> jobdescriptionstrings;
+  std::list<std::string> jobdescriptionfiles;
+  std::list<std::string> jobidinfiles;
+  std::list<std::string> status;
+
+  std::list<std::string> rejectdiscovery;
+  std::list<std::string> rejectmanagement;
+};