Back to index

nordugrid-arc-nox  1.1.0~rc6
Public Member Functions | Private Attributes | Static Private Attributes
Arc::Compiler_AREXClient Class Reference

A client class for the A-REX service. More...

#include <arex_client.h>

Collaboration diagram for Arc::Compiler_AREXClient:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 Compiler_AREXClient (std::string configFile="") throw (Compiler_AREXClientError)
 The constructor for the Compiler_AREXClient class.
 Compiler_AREXClient (const Arc::URL &url, const Arc::MCCConfig &cfg) throw (Compiler_AREXClientError)
 ~Compiler_AREXClient ()
 The destructor.
std::string submit (std::istream &jsdl_file, Compiler_AREXFileList &file_list, bool delegate=false) throw (Compiler_AREXClientError)
 Submit a job.
std::string stat (const std::string &jobid) throw (Compiler_AREXClientError)
 Query the status of a job.
void kill (const std::string &jobid) throw (Compiler_AREXClientError)
 Terminates a job.
void clean (const std::string &jobid) throw (Compiler_AREXClientError)
 Removes a job.
std::string sstat (void) throw (Compiler_AREXClientError)
 Query the status of a service.
ClientSOAPSOAP (void)

Private Attributes

Arc::Configclient_config
 The configuration.
Arc::MCCLoaderclient_loader
 The loader.
Arc::ClientSOAPclient
Arc::MCCclient_entry
 The entry into the client message chain.
Arc::NS arex_ns
 Namespaces.

Static Private Attributes

static Arc::Logger logger
 A logger for the A-REX client.

Detailed Description

A client class for the A-REX service.

This class is a client for the A-REX service (Arc Resource-coupled EXecution service). It provides methods for three operations on an A-REX service:

Definition at line 56 of file arex_client.h.


Constructor & Destructor Documentation

The constructor for the Compiler_AREXClient class.

This is the constructor for the Compiler_AREXClient class. It creates an A-REX client that corresponds to a specific A-REX service, which is specified in a configuration file. The configuration file also specifies how to set up the communication chain for the client. The location of the configuration file can be provided as a parameter to the method. If no such parameter is given, the environment variable ARC_Compiler_AREX_CONFIG is assumed to contain the location. If there is no such environment variable, the configuration file is assumed to be "arex_client.xml" in the current working directory.

Parameters:
configFileThe location of the configuration file.
Exceptions:
AnCompiler_AREXClientError object if an error occurs.

Definition at line 45 of file arex_client.cpp.

    :client_config(NULL),client_loader(NULL),client(NULL),client_entry(NULL)
  {
    logger.msg(Arc::INFO, "Creating an A-REX client");

    if (configFile=="" && getenv("ARC_Compiler_AREX_CONFIG"))
      configFile = getenv("ARC_Compiler_AREX_CONFIG");
    if (configFile=="")
      configFile = "./arex_client.xml";

    client_config = new Arc::Config(configFile.c_str());
    if(!*client_config) {
      logger.msg(Arc::ERROR, "Failed to load client configuration");
      throw Compiler_AREXClientError("Failed to load client configuration");
    }

    client_loader = new Arc::MCCLoader(*client_config);
    logger.msg(Arc::INFO, "Client side MCCs are loaded");
    client_entry = (*client_loader)["soap"];
    if(!client_entry) {
      logger.msg(Arc::ERROR, "Client chain does not have entry point");
      throw Compiler_AREXClientError("Client chain does not have entry point");
    }

    set_arex_namespaces(arex_ns);
  }

Here is the call graph for this function:

Definition at line 72 of file arex_client.cpp.

    :client_config(NULL),client_loader(NULL),client(NULL),client_entry(NULL) {

    logger.msg(Arc::INFO, "Creating an A-REX client");
    client = new Arc::ClientSOAP(cfg,url, 60);
    set_arex_namespaces(arex_ns);
  }

Here is the call graph for this function:

The destructor.

This is the destructor. It does what destructors usually do, cleans up...

Definition at line 81 of file arex_client.cpp.

  {
    if(client_loader) delete client_loader;
    if(client_config) delete client_config;
    if(client) delete client;
  }

Member Function Documentation

void Arc::Compiler_AREXClient::clean ( const std::string &  jobid) throw (Compiler_AREXClientError)

Removes a job.

This method sends a request to the A-REX service to remove a job from it's pool. If job is running it will be killed by service as well.

Parameters:
jobidThe Job ID of the job to remove.
Exceptions:
AnCompiler_AREXClientError object if an error occurs.

Definition at line 466 of file arex_client.cpp.

  {
    std::string result, faultstring;
    logger.msg(Arc::INFO, "Creating and sending request to terminate a job");
    
    Arc::PayloadSOAP req(arex_ns);
    Arc::XMLNode op = req.NewChild("a-rex:ChangeActivityStatus");
    Arc::XMLNode jobref = op.NewChild(Arc::XMLNode(jobid));
    Arc::XMLNode jobstate = op.NewChild("a-rex:NewStatus");
    jobstate.NewAttribute("bes-factory:state")="Finished";
    jobstate.NewChild("a-rex:state")="Deleted";
    // Send clean request
    Arc::PayloadSOAP* resp = NULL;
    if(client) {
      Arc::MCC_Status status = client->process("",&req,&resp);
      if(resp == NULL) {
        logger.msg(Arc::ERROR,"There was no SOAP response");
        throw Compiler_AREXClientError("There was no SOAP response");
      }
    } else if(client_entry) {
      Arc::Message reqmsg;
      Arc::Message repmsg;
      Arc::MessageAttributes attributes_req;
      Arc::MessageAttributes attributes_rep;
      Arc::MessageContext context;
      reqmsg.Payload(&req);
      reqmsg.Attributes(&attributes_req);
      reqmsg.Context(&context);
      repmsg.Attributes(&attributes_rep);
      repmsg.Context(&context);
      Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
      if(!status) {
        logger.msg(Arc::ERROR, "Job cleaning request failed");
        throw Compiler_AREXClientError("Job cleaning request failed");
      }
      logger.msg(Arc::INFO, "Job cleaning request succeed");
      if(repmsg.Payload() == NULL) {
        logger.msg(Arc::ERROR,
               "There was no response to a job cleaning request");
        throw Compiler_AREXClientError
       ("There was no response to the job cleaning request");
      }
      try {
        resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
      } catch(std::exception&) { };
      if(resp == NULL) {
        logger.msg(Arc::ERROR,
        "The response of a job cleaning request was not a SOAP message");
        delete repmsg.Payload();
        throw Compiler_AREXClientError("The response is not a SOAP message");
      }
    } else {
      throw Compiler_AREXClientError("There is no connection chain configured");
    };

    if(!((*resp)["ChangeActivityStatusResponse"])) {
      delete resp;
      Arc::XMLNode fs;
      (*resp)["Fault"]["faultstring"].New(fs);
      faultstring=(std::string)fs;
      if (faultstring!="")
        throw Compiler_AREXClientError(faultstring);
      if (result!="true")
        throw Compiler_AREXClientError("Job termination failed");
    };
    delete resp;
  }

Here is the call graph for this function:

void Arc::Compiler_AREXClient::kill ( const std::string &  jobid) throw (Compiler_AREXClientError)

Terminates a job.

This method sends a request to the A-REX service to terminate a job.

Parameters:
jobidThe Job ID of the job to terminate.
Exceptions:
AnCompiler_AREXClientError object if an error occurs.

Definition at line 395 of file arex_client.cpp.

  {
    std::string result, faultstring;
    logger.msg(Arc::INFO, "Creating and sending request to terminate a job");
    
    Arc::PayloadSOAP req(arex_ns);
    Arc::XMLNode jobref =
      req.NewChild("bes-factory:TerminateActivities").
      NewChild(Arc::XMLNode(jobid));
    
    // Send kill request
    Arc::PayloadSOAP* resp = NULL;
    if(client) {
      Arc::MCC_Status status = client->process(
         "http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/TerminateActivities",
         &req,&resp);
      if(resp == NULL) {
        logger.msg(Arc::ERROR,"There was no SOAP response");
        throw Compiler_AREXClientError("There was no SOAP response");
      }
    } else if(client_entry) {
      Arc::Message reqmsg;
      Arc::Message repmsg;
      Arc::MessageAttributes attributes_req;
      attributes_req.set("SOAP:ACTION","http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/TerminateActivities");
      Arc::MessageAttributes attributes_rep;
      Arc::MessageContext context;
      reqmsg.Payload(&req);
      reqmsg.Attributes(&attributes_req);
      reqmsg.Context(&context);
      repmsg.Attributes(&attributes_rep);
      repmsg.Context(&context);
      Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
      if(!status) {
        logger.msg(Arc::ERROR, "Job termination request failed");
        throw Compiler_AREXClientError("Job termination request failed");
      }
      logger.msg(Arc::INFO, "Job termination request succeed");
      if(repmsg.Payload() == NULL) {
        logger.msg(Arc::ERROR,
               "There was no response to a job termination request");
        throw Compiler_AREXClientError
       ("There was no response to the job termination request");
      }
      try {
        resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
      } catch(std::exception&) { };
      if(resp == NULL) {
        logger.msg(Arc::ERROR,
       "The response of a job termination request was not a SOAP message");
        delete repmsg.Payload();
        throw Compiler_AREXClientError("The response is not a SOAP message");
      }
    } else {
      throw Compiler_AREXClientError("There is no connection chain configured");
    };

    Arc::XMLNode cancelled, fs;
    (*resp)["TerminateActivitiesResponse"]
           ["Response"]["Cancelled"].New(cancelled);
    result = (std::string)cancelled;
    (*resp)["Fault"]["faultstring"].New(fs);
    faultstring=(std::string)fs;
    delete resp;
    if (faultstring!="")
      throw Compiler_AREXClientError(faultstring);
    if (result!="true")
      throw Compiler_AREXClientError("Job termination failed");
  }

Here is the call graph for this function:

Definition at line 125 of file arex_client.h.

{ return client; };

Here is the caller graph for this function:

Query the status of a service.

This method queries the A-REX service about it's status.

Returns:
The XML document representing status of the service.
Exceptions:
AnCompiler_AREXClientError object if an error occurs.

Definition at line 330 of file arex_client.cpp.

  {
    std::string state, faultstring;
    logger.msg(Arc::INFO, "Creating and sending a service status request");
    
    Arc::PayloadSOAP req(arex_ns);
    Arc::XMLNode jobref =
      req.NewChild("bes-factory:GetFactoryAttributesDocument");
    
    // Send status request
    Arc::PayloadSOAP* resp = NULL;
    if(client) {
      Arc::MCC_Status status = client->process(
         "http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/GetFactoryAttributesDocument",
         &req,&resp);
      if(resp == NULL) {
        logger.msg(Arc::ERROR,"There was no SOAP response");
        throw Compiler_AREXClientError("There was no SOAP response");
      }
    } else if(client_entry) {
      Arc::Message reqmsg;
      Arc::Message repmsg;
      Arc::MessageAttributes attributes_req;
      attributes_req.set("SOAP:ACTION","http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/GetFactoryAttributesDocument");
      Arc::MessageAttributes attributes_rep;
      Arc::MessageContext context;
      reqmsg.Payload(&req);
      reqmsg.Attributes(&attributes_req);
      reqmsg.Context(&context);
      repmsg.Attributes(&attributes_rep);
      repmsg.Context(&context);
      Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
      if(!status) {
        logger.msg(Arc::ERROR, "Service status request failed");
        throw Compiler_AREXClientError("Service status request failed");
      }
      logger.msg(Arc::INFO, "Service status request succeed");
      if(repmsg.Payload() == NULL) {
        logger.msg(Arc::ERROR, "There was no response to a service status request");
        throw Compiler_AREXClientError("There was no response");
      }
      try {
        resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
      } catch(std::exception&) { };
      if(resp == NULL) {
        logger.msg(Arc::ERROR,
               "The response of a service status request was not a SOAP message");
        delete repmsg.Payload();
        throw Compiler_AREXClientError("The response is not a SOAP message");
      }
    } else {
      throw Compiler_AREXClientError("There is no connection chain configured");
    };
    Arc::XMLNode st;
    (*resp)["GetFactoryAttributesDocumentResponse"]
           ["FactoryResourceAttributesDocument"].New(st);
    st.GetDoc(state);
    delete resp;
    if (state=="")
      throw Compiler_AREXClientError("The service status could not be retrieved");
    else
      return state;
  }

Here is the call graph for this function:

std::string Arc::Compiler_AREXClient::stat ( const std::string &  jobid) throw (Compiler_AREXClientError)

Query the status of a job.

This method queries the A-REX service about the status of a job.

Parameters:
jobidThe Job ID of the job.
Returns:
The status of the job.
Exceptions:
AnCompiler_AREXClientError object if an error occurs.

Definition at line 255 of file arex_client.cpp.

  {
    std::string state, substate, faultstring;
    logger.msg(Arc::INFO, "Creating and sending a status request");
    
    Arc::PayloadSOAP req(arex_ns);
    Arc::XMLNode jobref =
      req.NewChild("bes-factory:GetActivityStatuses").
      NewChild(Arc::XMLNode(jobid));
    
    // Send status request
    Arc::PayloadSOAP* resp = NULL;

    if(client) {
      Arc::MCC_Status status = client->process(
          "http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/GetActivityStatuses",
          &req,&resp);
      if(resp == NULL) {
        logger.msg(Arc::ERROR,"There was no SOAP response");
        throw Compiler_AREXClientError("There was no SOAP response");
      }
    } else if(client_entry) {
      Arc::Message reqmsg;
      Arc::Message repmsg;
      Arc::MessageAttributes attributes_req;
      attributes_req.set("SOAP:ACTION","http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/GetActivityStatuses");
      Arc::MessageAttributes attributes_rep;
      Arc::MessageContext context;
      reqmsg.Payload(&req);
      reqmsg.Attributes(&attributes_req);
      reqmsg.Context(&context);
      repmsg.Attributes(&attributes_rep);
      repmsg.Context(&context);
      Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
      if(!status) {
        logger.msg(Arc::ERROR, "Status request failed");
        throw Compiler_AREXClientError("Status request failed");
      }
      logger.msg(Arc::INFO, "Status request succeed");
      if(repmsg.Payload() == NULL) {
        logger.msg(Arc::ERROR, "There was no response to a status request");
        throw Compiler_AREXClientError("There was no response");
      }
      try {
        resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
      } catch(std::exception&) { };
      if(resp == NULL) {
        logger.msg(Arc::ERROR,
               "The response to a status request was not a SOAP message");
        delete repmsg.Payload();
        throw Compiler_AREXClientError("The response is not a SOAP message");
      }
    } else {
      throw Compiler_AREXClientError("There is no connection chain configured");
    };
    Arc::XMLNode st, fs;
    (*resp)["GetActivityStatusesResponse"]["Response"]
           ["ActivityStatus"].New(st);
    state = (std::string)st.Attribute("state");
    Arc::XMLNode sst;
    (*resp)["GetActivityStatusesResponse"]["Response"]
           ["ActivityStatus"]["state"].New(sst);
    substate = (std::string)sst;
    (*resp)["Fault"]["faultstring"].New(fs);
    faultstring=(std::string)fs;
    delete resp;
    if (faultstring!="")
      throw Compiler_AREXClientError(faultstring);
    else if (state=="")
      throw Compiler_AREXClientError("The job status could not be retrieved");
    else
      return state+"/"+substate;
  }

Here is the call graph for this function:

Here is the caller graph for this function:

std::string Arc::Compiler_AREXClient::submit ( std::istream &  jsdl_file,
Compiler_AREXFileList file_list,
bool  delegate = false 
) throw (Compiler_AREXClientError)

Submit a job.

This method submits a job to the A-REX service corresponding to this client instance.

Parameters:
jsdl_fileAn input stream from which the JSDL file for the job can be read.
Returns:
The Job ID of the the submitted job.
Exceptions:
AnCompiler_AREXClientError object if an error occurs.

Definition at line 88 of file arex_client.cpp.

  {
    std::string jobid, faultstring;
    file_list.resize(0);

    logger.msg(Arc::INFO, "Creating and sending request");

    // Create job request
    /*
      bes-factory:CreateActivity
        bes-factory:ActivityDocument
          jsdl:JobDefinition
    */
    Arc::PayloadSOAP req(arex_ns);
    Arc::XMLNode op = req.NewChild("bes-factory:CreateActivity");
    Arc::XMLNode act_doc = op.NewChild("bes-factory:ActivityDocument");
    std::string jsdl_str; 
    std::getline<char>(jsdl_file,jsdl_str,0);
    act_doc.NewChild(Arc::XMLNode(jsdl_str));
    act_doc.Child(0).Namespaces(arex_ns); // Unify namespaces
    Arc::PayloadSOAP* resp = NULL;

    XMLNode ds = act_doc["jsdl:JobDefinition"]["jsdl:JobDescription"]["jsdl:DataStaging"];
    for(;(bool)ds;ds=ds[1]) {
      // FilesystemName - ignore
      // CreationFlag - ignore
      // DeleteOnTermination - ignore
      XMLNode source = ds["jsdl:Source"];
      XMLNode target = ds["jsdl:Target"];
      if((bool)source) {
        std::string s_name = ds["jsdl:FileName"];
        if(!s_name.empty()) {
          XMLNode x_url = source["jsdl:URI"];
          std::string s_url = x_url;
          if(s_url.empty()) {
            s_url="./"+s_name;
          } else {
            URL u_url(s_url);
            if(!u_url) {
              if(s_url[0] != '/') s_url="./"+s_url;
            } else {
              if(u_url.Protocol() == "file") {
                s_url=u_url.Path();
                if(s_url[0] != '/') s_url="./"+s_url;
              } else {
                s_url.resize(0);
              };
            };
          };
          if(!s_url.empty()) {
            x_url.Destroy();
            Compiler_AREXFile file(s_name,s_url);
            file_list.push_back(file);
          };
        };
      };
    }; 
    act_doc.GetXML(jsdl_str);
    logger.msg(Arc::DEBUG, "Job description to be sent: %s",jsdl_str);

    // Try to figure out which credentials are used
    // TODO: Method used is unstable beacuse it assumes some predefined 
    // structure of configuration file. Maybe there should be some 
    // special methods of ClientTCP class introduced.
    std::string deleg_cert;
    std::string deleg_key;
    if(delegate) {
      client->Load(); // Make sure chain is ready
      Arc::XMLNode tls_cfg = find_xml_node((client->GetConfig())["Chain"],"Component","name","tls.client");
      if(tls_cfg) {
        deleg_cert=(std::string)(tls_cfg["ProxyPath"]);
        if(deleg_cert.empty()) {
          deleg_cert=(std::string)(tls_cfg["CertificatePath"]);
          deleg_key=(std::string)(tls_cfg["KeyPath"]);
        } else {
          deleg_key=deleg_cert;
        };
      };
      if(deleg_cert.empty() || deleg_key.empty()) {
std::string s;
client->GetConfig().GetXML(s);
std::cerr<<s<<std::endl;
        logger.msg(Arc::ERROR,"Failed to find delegation credentials in client configuration");
        throw Compiler_AREXClientError("Failed to find delegation credentials in client configuration");
      };
    };
    // Send job request + delegation
    if(client) {
      {
        if(delegate) {
          Arc::DelegationProviderSOAP deleg(deleg_cert,deleg_key);
          logger.msg(Arc::INFO, "Initiating delegation procedure");
          if(!deleg.DelegateCredentialsInit(*(client->GetEntry()),&(client->GetContext()))) {
            logger.msg(Arc::ERROR,"Failed to initiate delegation");
            throw Compiler_AREXClientError("Failed to initiate delegation");
          };
          deleg.DelegatedToken(op);
        };
      };
      Arc::MCC_Status status = client->process(
         "http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/CreateActivity",
         &req,&resp);
      if(!status) {
        logger.msg(Arc::ERROR, "Submission request failed");
        throw Compiler_AREXClientError("Submission request failed");
      }
      if(resp == NULL) {
        logger.msg(Arc::ERROR,"There was no SOAP response");
        throw Compiler_AREXClientError("There was no SOAP response");
      };
    } else if (client_entry) {
      Arc::Message reqmsg;
      Arc::Message repmsg;
      Arc::MessageAttributes attributes_req;
      attributes_req.set("SOAP:ACTION","http://schemas.ggf.org/bes/2006/08/bes-factory/BESFactoryPortType/CreateActivity");
      Arc::MessageAttributes attributes_rep;
      Arc::MessageContext context;
      {
        if(delegate) {
          Arc::DelegationProviderSOAP deleg(deleg_cert,deleg_key);
          logger.msg(Arc::INFO, "Initiating delegation procedure");
          if(!deleg.DelegateCredentialsInit(*client_entry,&context)) {
            logger.msg(Arc::ERROR,"Failed to initiate delegation");
            throw Compiler_AREXClientError("Failed to initiate delegation");
          };
          deleg.DelegatedToken(op);
        };
      };
      reqmsg.Payload(&req);
      reqmsg.Attributes(&attributes_req);
      reqmsg.Context(&context);
      repmsg.Attributes(&attributes_rep);
      repmsg.Context(&context);
      Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
      if(!status) {
        logger.msg(Arc::ERROR, "Submission request failed");
        throw Compiler_AREXClientError("Submission request failed");
      }
      logger.msg(Arc::INFO, "Submission request succeed");
      if(repmsg.Payload() == NULL) {
        logger.msg(Arc::ERROR, "There was no response to a submission request");
        throw Compiler_AREXClientError("There was no response to the submission request");
      }
      try {
        resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
      } catch(std::exception&) { };
      if(resp == NULL) {
        logger.msg(Arc::ERROR,"A response to a submission request was not a SOAP message");
        delete repmsg.Payload();
        throw Compiler_AREXClientError("The response to the submission request was not a SOAP message");
      };
    } else {
      throw Compiler_AREXClientError("There is no connection chain configured");
    };
    Arc::XMLNode id, fs;
    (*resp)["CreateActivityResponse"]["ActivityIdentifier"].New(id);
    (*resp)["Fault"]["faultstring"].New(fs);
    id.GetDoc(jobid);
    faultstring=(std::string)fs;
    delete resp;
    if (faultstring=="")
      return jobid;
    else
      throw Compiler_AREXClientError(faultstring);
  }

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Namespaces.

A map containing namespaces.

Definition at line 152 of file arex_client.h.

Definition at line 141 of file arex_client.h.

The configuration.

A configuration object containing information about how to set up this A-REX client.

Definition at line 125 of file arex_client.h.

The entry into the client message chain.

This is a pointer to the message chain components (MCC) where messages sent from this client enters the message chain.

Definition at line 147 of file arex_client.h.

The loader.

A loader object that loads and connects the appropriate components according to the configuration object.

Definition at line 139 of file arex_client.h.

A logger for the A-REX client.

This is a logger to which all logging messages from the A-REX client are sent.

Definition at line 158 of file arex_client.h.


The documentation for this class was generated from the following files: