1 // Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include <libxml/parser.h>
25 #include "Launcher_XML_Persistence.hxx"
26 #include "Launcher_Job_Command.hxx"
27 #include "Launcher_Job_CommandSALOME.hxx"
28 #include "Launcher_Job_YACSFile.hxx"
29 #include "Launcher_Job_PythonSALOME.hxx"
37 XML_Persistence::loadJobs(const char* jobs_file)
39 // Step 1: check jobs_file read access
40 FILE* xml_file = fopen(jobs_file, "r");
43 std::string error = "Error opening jobs_file in SALOME_Launcher::loadJobs: " + std::string(jobs_file);
44 LAUNCHER_INFOS(error);
45 throw LauncherException(error);
48 // Step 2: read xml file
49 xmlDocPtr doc = xmlReadFile(jobs_file, NULL, 0);
52 std::string error = "Error in xmlReadFile in SALOME_Launcher::loadJobs, could not parse file: " + std::string(jobs_file);
53 LAUNCHER_INFOS(error);
55 throw LauncherException(error);
59 list<Job *> jobs_list;
60 xmlNodePtr root_node = xmlDocGetRootElement(doc);
61 if (xmlStrToString(root_node->name) == "jobs")
63 xmlNodePtr xmlCurrentNode = root_node->xmlChildrenNode;
64 while(xmlCurrentNode != NULL)
66 if (xmlStrToString(xmlCurrentNode->name) == "job")
68 LAUNCHER_INFOS("A job is found");
69 Job * new_job = createJobFromXmlNode(xmlCurrentNode);
70 jobs_list.push_back(new_job);
72 xmlCurrentNode = xmlCurrentNode->next;
79 std::string error = "Error in xml file, could not find root_node named jobs: " + std::string(jobs_file);
80 LAUNCHER_INFOS(error);
81 throw LauncherException(error);
92 XML_Persistence::saveJobs(const char* jobs_file, const list<const Job *> & jobs_list)
94 // Step 1: check jobs_file write access
95 FILE* xml_file = fopen(jobs_file, "w");
98 std::string error = "Error opening jobs_file in SALOME_Launcher::saveJobs: " + std::string(jobs_file);
99 LAUNCHER_INFOS(error);
100 throw LauncherException(error);
103 // Step 2: First lines
104 xmlKeepBlanksDefault(0);
105 xmlDocPtr doc = xmlNewDoc(xmlCharStrdup("1.0"));
106 xmlNodePtr root_node = xmlNewNode(NULL, xmlCharStrdup("jobs"));
107 xmlDocSetRootElement(doc, root_node);
108 xmlNodePtr doc_comment = xmlNewDocComment(doc, xmlCharStrdup("SALOME Launcher save jobs file"));
109 xmlAddPrevSibling(root_node, doc_comment);
111 // Step 3: For each job write it on the xml document
112 // We could put a mutex but are not foing to do that currently
113 list<const Job *>::const_iterator it_job;
114 for (it_job = jobs_list.begin(); it_job != jobs_list.end(); it_job++)
116 addJobToXmlDocument(root_node, **it_job);
119 // Final step: write file
120 int isOk = xmlSaveFormatFile(jobs_file, doc, 1);
123 std::string error = "Error during xml file saving in SALOME_Launcher::saveJobs: " + std::string(jobs_file);
124 LAUNCHER_INFOS(error);
127 throw LauncherException(error);
133 LAUNCHER_MESSAGE("SALOME_Launcher::saveJobs : WRITING DONE!");
137 XML_Persistence::addJobToXmlDocument(xmlNodePtr root_node, const Job & job)
140 xmlNodePtr job_node = addNode(root_node, "job", "");
141 addAttr(job_node, "type", job.getJobType());
142 addAttr(job_node, "name", job.getJobName());
145 xmlNodePtr node = addNode(job_node, "user_part", "");
147 addNode(node, "job_file", job.getJobFile());
148 if (!job.getEnvFile().empty())
149 addNode(node, "env_file", job.getEnvFile());
150 if (!job.getWorkDirectory().empty())
151 addNode(node, "work_directory", job.getWorkDirectory());
152 if (!job.getLocalDirectory().empty())
153 addNode(node, "local_directory", job.getLocalDirectory());
154 if (!job.getResultDirectory().empty())
155 addNode(node, "result_directory", job.getResultDirectory());
156 if (!job.getPreCommand().empty())
157 addNode(node, "pre_command", job.getPreCommand());
159 // Parameters for COORM
160 if (!job.getLauncherFile().empty())
161 addNode(node, "launcher_file", job.getLauncherFile());
162 if (!job.getLauncherArgs().empty())
163 addNode(node, "launcher_args", job.getLauncherArgs());
166 if ( ! (job.get_in_files().empty() && job.get_out_files().empty()) )
168 xmlNodePtr files_node = addNode(node, "files", "");
169 list<string> in_files = job.get_in_files();
170 list<string> out_files = job.get_out_files();
171 for(list<string>::iterator it = in_files.begin(); it != in_files.end(); it++)
172 addNode(files_node, "in_file", *it);
173 for(list<string>::iterator it = out_files.begin(); it != out_files.end(); it++)
174 addNode(files_node, "out_file", *it);
178 resourceParams resource_params = job.getResourceRequiredParams();
179 xmlNodePtr res_node = addNode(node, "resource_params", "");
180 addNode(res_node, "name", resource_params.name);
181 if (!resource_params.hostname.empty())
182 addNode(res_node, "hostname", resource_params.hostname);
183 if (!resource_params.OS.empty())
184 addNode(res_node, "OS", resource_params.OS);
185 if (resource_params.nb_proc > 0)
186 addNumericalNode(res_node, "nb_proc", resource_params.nb_proc);
187 if (resource_params.nb_node > 0)
188 addNumericalNode(res_node, "nb_node", resource_params.nb_node);
189 if (resource_params.nb_proc_per_node > 0)
190 addNumericalNode(res_node, "nb_proc_per_node", resource_params.nb_proc_per_node);
191 if (resource_params.cpu_clock > 0)
192 addNumericalNode(res_node, "cpu_clock", resource_params.cpu_clock);
193 if (resource_params.mem_mb > 0)
194 addNumericalNode(res_node, "mem_mb", resource_params.mem_mb);
196 if (!job.getMaximumDuration().empty())
197 addNode(node, "maximum_duration", job.getMaximumDuration());
198 if (!job.getQueue().empty())
199 addNode(node, "queue", job.getQueue());
200 if (!job.getPartition().empty())
201 addNode(node, "partition", job.getPartition());
202 if (job.getExclusive())
203 addNode(node, "exclusive", job.getExclusiveStr());
204 if (job.getMemPerCpu() > 0)
205 addNumericalNode(res_node, "mem_per_cpu", job.getMemPerCpu());
206 if (!job.getWCKey().empty())
207 addNode(node, "wckey", job.getWCKey());
208 if (!job.getExtraParams().empty())
209 addNode(node, "extra_params", job.getExtraParams());
211 // Specific parameters part
212 map<string, string> specific_parameters = job.getSpecificParameters();
213 if (!specific_parameters.empty())
215 xmlNodePtr specific_parameters_node = addNode(node, "specific_parameters", "");
216 for(map<string, string>::iterator it = specific_parameters.begin();
217 it != specific_parameters.end();
220 xmlNodePtr specific_parameter_node = addNode(specific_parameters_node,
221 "specific_parameter", "");
222 addNode(specific_parameter_node, "name", it->first);
223 addNode(specific_parameter_node, "value", it->second);
228 xmlNodePtr run_node = addNode(job_node, "run_part", "");
229 addNode(run_node, "job_state", job.getState());
230 addNode(run_node, "job_reference", job.getReference());
234 XML_Persistence::createJobFromXmlNode(xmlNodePtr job_node)
236 Launcher::Job * new_job;
239 string job_name = getAttrValue(job_node, "name");
240 if (job_name.empty())
241 throw LauncherException("Invalid job: name is not defined");
242 string job_type = getAttrValue(job_node, "type");
243 if (job_type.empty())
244 throw LauncherException(string("Invalid job \"") + job_name + "\": type is not defined");
245 if (job_type == Launcher::Job_Command::TYPE_NAME)
246 new_job = new Launcher::Job_Command();
247 else if (job_type == Launcher::Job_CommandSALOME::TYPE_NAME)
248 new_job = new Launcher::Job_CommandSALOME();
249 else if (job_type == Launcher::Job_YACSFile::TYPE_NAME)
250 new_job = new Launcher::Job_YACSFile();
251 else if (job_type == Launcher::Job_PythonSALOME::TYPE_NAME)
252 new_job = new Launcher::Job_PythonSALOME();
255 string error = string("Invalid job \"") + job_name + "\": invalid type \"" + job_type + "\"";
256 throw LauncherException(error);
258 new_job->setJobName(job_name);
262 xmlNodePtr current_node = xmlFirstElementChild(job_node);
263 bool user_ok = false;
265 while (current_node != NULL)
267 string node_name = xmlStrToString(current_node->name);
268 if (node_name == "user_part")
270 parseUserNode(new_job, current_node);
273 else if (node_name == "run_part")
275 parseRunNode(new_job, current_node);
279 throw LauncherException(string("invalid node \"") + node_name + "\"");
280 current_node = xmlNextElementSibling(current_node);
282 if (!user_ok) throw LauncherException("missing user part");
283 if (!run_ok) throw LauncherException("missing run part");
285 catch (const LauncherException & exc)
288 string error = string("Invalid job \"") + job_name + "\": " + exc.msg;
289 throw LauncherException(error);
296 XML_Persistence::parseUserNode(Job * new_job, xmlNodePtr user_node)
298 xmlNodePtr current_node = xmlFirstElementChild(user_node);
299 bool job_file_ok = false;
300 while (current_node != NULL)
302 string node_name = xmlStrToString(current_node->name);
303 if (node_name == "job_file")
305 new_job->setJobFile(getNodeContent(current_node));
308 else if (node_name == "env_file")
309 new_job->setEnvFile(getNodeContent(current_node));
310 else if (node_name == "pre_command")
311 new_job->setPreCommand(getNodeContent(current_node));
312 else if (node_name == "work_directory")
313 new_job->setWorkDirectory(getNodeContent(current_node));
314 else if (node_name == "local_directory")
315 new_job->setLocalDirectory(getNodeContent(current_node));
316 else if (node_name == "result_directory")
317 new_job->setResultDirectory(getNodeContent(current_node));
318 else if (node_name == "launcher_file") // For COORM
319 new_job->setLauncherFile(getNodeContent(current_node));
320 else if (node_name == "launcher_args") // For COORM
321 new_job->setLauncherArgs(getNodeContent(current_node));
322 else if (node_name == "files")
324 // Get in and out files
325 xmlNodePtr file_node = xmlFirstElementChild(current_node);
326 while (file_node != NULL)
328 string file_node_name = xmlStrToString(file_node->name);
329 if (file_node_name == "in_file")
330 new_job->add_in_file(getNodeContent(file_node));
331 else if (file_node_name == "out_file")
332 new_job->add_out_file(getNodeContent(file_node));
334 throw LauncherException(string("invalid node \"") + file_node_name + "\"");
335 file_node = xmlNextElementSibling(file_node);
338 else if (node_name == "resource_params")
339 parseResourceNode(new_job, current_node);
340 else if (node_name == "maximum_duration")
341 new_job->setMaximumDuration(getNodeContent(current_node));
342 else if (node_name == "queue")
343 new_job->setQueue(getNodeContent(current_node));
344 else if (node_name == "partition")
345 new_job->setPartition(getNodeContent(current_node));
346 else if (node_name == "exclusive")
347 new_job->setExclusiveStr(getNodeContent(current_node));
348 else if (node_name == "mem_per_cpu")
349 new_job->setMemPerCpu(getNumericalNodeContent<unsigned long>(current_node));
350 else if (node_name == "wckey")
351 new_job->setWCKey(getNodeContent(current_node));
352 else if (node_name == "extra_params")
353 new_job->setExtraParams(getNodeContent(current_node));
354 else if (node_name == "specific_parameters")
356 // Get specific parameters
357 xmlNodePtr parameter_node = xmlFirstElementChild(current_node);
358 while (parameter_node != NULL)
360 string parameter_node_name = xmlStrToString(parameter_node->name);
361 if (parameter_node_name == "specific_parameter")
363 xmlNodePtr inparam_node = xmlFirstElementChild(parameter_node);
366 while (inparam_node != NULL)
368 string inparam_node_name = xmlStrToString(inparam_node->name);
369 if (inparam_node_name == "name")
370 name = getNodeContent(inparam_node);
371 else if (inparam_node_name == "value")
372 value = getNodeContent(inparam_node);
374 throw LauncherException(string("invalid node \"") + inparam_node_name + "\"");
375 inparam_node = xmlNextElementSibling(inparam_node);
377 if (name.empty()) throw LauncherException("missing parameter name");
378 if (value.empty()) throw LauncherException("missing parameter value");
379 new_job->addSpecificParameter(name, value);
382 throw LauncherException(string("invalid node \"") + parameter_node_name + "\"");
383 parameter_node = xmlNextElementSibling(parameter_node);
387 throw LauncherException(string("invalid node \"") + node_name + "\"");
388 current_node = xmlNextElementSibling(current_node);
390 if (!job_file_ok) throw LauncherException("missing job file");
394 XML_Persistence::parseResourceNode(Job * new_job, xmlNodePtr res_node)
397 xmlNodePtr current_node = xmlFirstElementChild(res_node);
398 while (current_node != NULL)
400 string node_name = xmlStrToString(current_node->name);
401 if (node_name == "name")
402 p.name = getNodeContent(current_node);
403 else if (node_name == "hostname")
404 p.hostname = getNodeContent(current_node);
405 else if (node_name == "OS")
406 p.OS = getNodeContent(current_node);
407 else if (node_name == "nb_proc")
408 p.nb_proc = getNumericalNodeContent<long>(current_node);
409 else if (node_name == "nb_node")
410 p.nb_node = getNumericalNodeContent<long>(current_node);
411 else if (node_name == "nb_proc_per_node")
412 p.nb_proc_per_node = getNumericalNodeContent<long>(current_node);
413 else if (node_name == "cpu_clock")
414 p.cpu_clock = getNumericalNodeContent<long>(current_node);
415 else if (node_name == "mem_mb")
416 p.mem_mb = getNumericalNodeContent<long>(current_node);
417 else if (node_name == "mem_per_cpu")
418 new_job->setMemPerCpu(getNumericalNodeContent<long>(current_node));
420 throw LauncherException(string("invalid node \"") + node_name + "\"");
421 current_node = xmlNextElementSibling(current_node);
423 new_job->setResourceRequiredParams(p);
427 XML_Persistence::parseRunNode(Job * new_job, xmlNodePtr run_node)
429 xmlNodePtr current_node = xmlFirstElementChild(run_node);
430 while (current_node != NULL)
432 string node_name = xmlStrToString(current_node->name);
433 if (node_name == "job_state")
434 new_job->setState(getNodeContent(current_node));
435 else if (node_name == "resource_choosed_name")
437 // This parameter was present in older versions of Salome. Now we just silently ignore it.
439 else if (node_name == "job_reference")
440 new_job->setReference(getNodeContent(current_node));
442 throw LauncherException(string("invalid node \"") + node_name + "\"");
443 current_node = xmlNextElementSibling(current_node);
448 XML_Persistence::getAttrValue(xmlNodePtr node, const string & attrName)
451 xmlChar * xmlAttrName = xmlCharStrdup(attrName.c_str());
452 xmlChar * xmlAttrValue = xmlGetProp(node, xmlAttrName);
453 if (xmlAttrValue != NULL) attrValue = (const char *)xmlAttrValue;
454 xmlFree(xmlAttrName);
455 xmlFree(xmlAttrValue);
460 XML_Persistence::xmlStrToString(const xmlChar * xmlStr)
462 return string((const char *)xmlStr);
466 XML_Persistence::getNodeContent(xmlNodePtr node)
469 xmlChar * xmlStrContent = xmlNodeGetContent(node);
470 if (xmlStrContent != NULL) nodeContent = (const char *)xmlStrContent;
471 xmlFree(xmlStrContent);
477 XML_Persistence::getNumericalNodeContent(xmlNodePtr node)
480 istringstream nodeContentStream(getNodeContent(node));
481 if (!(nodeContentStream >> result))
482 throw LauncherException(xmlStrToString(node->name) + " parameter is not correct");
487 XML_Persistence::addNode(xmlNodePtr father, const string & name, const string & content)
489 xmlChar * xmlStrName = xmlCharStrdup(name.c_str());
490 xmlChar * xmlStrContent = NULL;
491 if (!content.empty())
492 xmlStrContent = xmlCharStrdup(content.c_str());
493 xmlNodePtr node = xmlNewChild(father, NULL, xmlStrName, xmlStrContent);
495 xmlFree(xmlStrContent);
501 XML_Persistence::addNumericalNode(xmlNodePtr father, const string & name, T content)
503 ostringstream nodeContentStream;
504 nodeContentStream << content;
505 return addNode(father, name, nodeContentStream.str());
509 XML_Persistence::addAttr(xmlNodePtr node, const string & name, const string & value)
511 xmlChar * xmlStrName = xmlCharStrdup(name.c_str());
512 xmlChar * xmlStrValue = xmlCharStrdup(value.c_str());
513 xmlNewProp(node, xmlStrName, xmlStrValue);
515 xmlFree(xmlStrValue);
519 XML_Persistence::createJobFromString(const std::string& jobDump)
522 doc = xmlReadMemory(jobDump.c_str(), jobDump.length(), "noname.xml", NULL, 0);
525 std::string error = "Error in xmlReadMemory in XML_Persistence::createJobFromString, could not parse string: " + jobDump;
526 LAUNCHER_INFOS(error);
527 throw LauncherException(error);
532 xmlNodePtr root_node = xmlDocGetRootElement(doc);
533 if (xmlStrToString(root_node->name) == "jobs")
535 xmlNodePtr xmlCurrentNode = root_node->xmlChildrenNode;
536 while(xmlCurrentNode != NULL && result == NULL)
538 if (xmlStrToString(xmlCurrentNode->name) == "job")
540 LAUNCHER_INFOS("A job is found");
541 result = createJobFromXmlNode(xmlCurrentNode);
543 xmlCurrentNode = xmlCurrentNode->next;
549 std::string error = "Error while parsing job dump: " + jobDump;
550 LAUNCHER_INFOS(error);
551 throw LauncherException(error);
560 XML_Persistence::dumpJob(const Job& job)
563 xmlKeepBlanksDefault(0);
564 xmlDocPtr doc = xmlNewDoc(xmlCharStrdup("1.0"));
565 xmlNodePtr root_node = xmlNewNode(NULL, xmlCharStrdup("jobs"));
566 xmlDocSetRootElement(doc, root_node);
567 xmlNodePtr doc_comment = xmlNewDocComment(doc, xmlCharStrdup("SALOME Launcher job"));
568 xmlAddPrevSibling(root_node, doc_comment);
570 addJobToXmlDocument(root_node, job);
572 // Final step: write to result
575 xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
578 result = (const char*) xmlbuff;