1 // Copyright (C) 2007-2015 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_YACSFile.hxx"
28 #include "Launcher_Job_PythonSALOME.hxx"
36 XML_Persistence::loadJobs(const char* jobs_file)
38 // Step 1: check jobs_file read access
39 FILE* xml_file = fopen(jobs_file, "r");
42 std::string error = "Error opening jobs_file in SALOME_Launcher::loadJobs: " + std::string(jobs_file);
43 LAUNCHER_INFOS(error);
44 throw LauncherException(error);
47 // Step 2: read xml file
48 xmlDocPtr doc = xmlReadFile(jobs_file, NULL, 0);
51 std::string error = "Error in xmlReadFile in SALOME_Launcher::loadJobs, could not parse file: " + std::string(jobs_file);
52 LAUNCHER_INFOS(error);
54 throw LauncherException(error);
58 list<Job *> jobs_list;
59 xmlNodePtr root_node = xmlDocGetRootElement(doc);
60 if (xmlStrToString(root_node->name) == "jobs")
62 xmlNodePtr xmlCurrentNode = root_node->xmlChildrenNode;
63 while(xmlCurrentNode != NULL)
65 if (xmlStrToString(xmlCurrentNode->name) == "job")
67 LAUNCHER_INFOS("A job is found");
68 Job * new_job = createJobFromXmlNode(xmlCurrentNode);
69 jobs_list.push_back(new_job);
71 xmlCurrentNode = xmlCurrentNode->next;
78 std::string error = "Error in xml file, could not find root_node named jobs: " + std::string(jobs_file);
79 LAUNCHER_INFOS(error);
80 throw LauncherException(error);
91 XML_Persistence::saveJobs(const char* jobs_file, const list<const Job *> & jobs_list)
93 // Step 1: check jobs_file write access
94 FILE* xml_file = fopen(jobs_file, "w");
97 std::string error = "Error opening jobs_file in SALOME_Launcher::saveJobs: " + std::string(jobs_file);
98 LAUNCHER_INFOS(error);
99 throw LauncherException(error);
102 // Step 2: First lines
103 xmlKeepBlanksDefault(0);
104 xmlDocPtr doc = xmlNewDoc(xmlCharStrdup("1.0"));
105 xmlNodePtr root_node = xmlNewNode(NULL, xmlCharStrdup("jobs"));
106 xmlDocSetRootElement(doc, root_node);
107 xmlNodePtr doc_comment = xmlNewDocComment(doc, xmlCharStrdup("SALOME Launcher save jobs file"));
108 xmlAddPrevSibling(root_node, doc_comment);
110 // Step 3: For each job write it on the xml document
111 // We could put a mutex but are not foing to do that currently
112 list<const Job *>::const_iterator it_job;
113 for (it_job = jobs_list.begin(); it_job != jobs_list.end(); it_job++)
115 addJobToXmlDocument(root_node, **it_job);
118 // Final step: write file
119 int isOk = xmlSaveFormatFile(jobs_file, doc, 1);
122 std::string error = "Error during xml file saving in SALOME_Launcher::saveJobs: " + std::string(jobs_file);
123 LAUNCHER_INFOS(error);
126 throw LauncherException(error);
132 LAUNCHER_MESSAGE("SALOME_Launcher::saveJobs : WRITING DONE!");
136 XML_Persistence::addJobToXmlDocument(xmlNodePtr root_node, const Job & job)
139 xmlNodePtr job_node = addNode(root_node, "job", "");
140 addAttr(job_node, "type", job.getJobType());
141 addAttr(job_node, "name", job.getJobName());
144 xmlNodePtr node = addNode(job_node, "user_part", "");
146 addNode(node, "job_file", job.getJobFile());
147 if (!job.getEnvFile().empty())
148 addNode(node, "env_file", job.getEnvFile());
149 if (!job.getWorkDirectory().empty())
150 addNode(node, "work_directory", job.getWorkDirectory());
151 if (!job.getLocalDirectory().empty())
152 addNode(node, "local_directory", job.getLocalDirectory());
153 if (!job.getResultDirectory().empty())
154 addNode(node, "result_directory", job.getResultDirectory());
156 // Parameters for COORM
157 if (!job.getLauncherFile().empty())
158 addNode(node, "launcher_file", job.getLauncherFile());
159 if (!job.getLauncherArgs().empty())
160 addNode(node, "launcher_args", job.getLauncherArgs());
163 if ( ! (job.get_in_files().empty() && job.get_out_files().empty()) )
165 xmlNodePtr files_node = addNode(node, "files", "");
166 list<string> in_files = job.get_in_files();
167 list<string> out_files = job.get_out_files();
168 for(list<string>::iterator it = in_files.begin(); it != in_files.end(); it++)
169 addNode(files_node, "in_file", *it);
170 for(list<string>::iterator it = out_files.begin(); it != out_files.end(); it++)
171 addNode(files_node, "out_file", *it);
175 resourceParams resource_params = job.getResourceRequiredParams();
176 xmlNodePtr res_node = addNode(node, "resource_params", "");
177 addNode(res_node, "name", resource_params.name);
178 if (!resource_params.hostname.empty())
179 addNode(res_node, "hostname", resource_params.hostname);
180 if (!resource_params.OS.empty())
181 addNode(res_node, "OS", resource_params.OS);
182 if (resource_params.nb_proc > 0)
183 addNumericalNode(res_node, "nb_proc", resource_params.nb_proc);
184 if (resource_params.nb_node > 0)
185 addNumericalNode(res_node, "nb_node", resource_params.nb_node);
186 if (resource_params.nb_proc_per_node > 0)
187 addNumericalNode(res_node, "nb_proc_per_node", resource_params.nb_proc_per_node);
188 if (resource_params.cpu_clock > 0)
189 addNumericalNode(res_node, "cpu_clock", resource_params.cpu_clock);
190 if (resource_params.mem_mb > 0)
191 addNumericalNode(res_node, "mem_mb", resource_params.mem_mb);
193 if (!job.getMaximumDuration().empty())
194 addNode(node, "maximum_duration", job.getMaximumDuration());
195 if (!job.getQueue().empty())
196 addNode(node, "queue", job.getQueue());
197 if (job.getExclusive())
198 addNode(node, "exclusive", job.getExclusiveStr());
199 if (job.getMemPerCpu() > 0)
200 addNumericalNode(res_node, "mem_per_cpu", job.getMemPerCpu());
201 if (!job.getWCKey().empty())
202 addNode(node, "wckey", job.getWCKey());
203 if (!job.getExtraParams().empty())
204 addNode(node, "extra_params", job.getExtraParams());
206 // Specific parameters part
207 map<string, string> specific_parameters = job.getSpecificParameters();
208 if (!specific_parameters.empty())
210 xmlNodePtr specific_parameters_node = addNode(node, "specific_parameters", "");
211 for(map<string, string>::iterator it = specific_parameters.begin();
212 it != specific_parameters.end();
215 xmlNodePtr specific_parameter_node = addNode(specific_parameters_node,
216 "specific_parameter", "");
217 addNode(specific_parameter_node, "name", it->first);
218 addNode(specific_parameter_node, "value", it->second);
223 xmlNodePtr run_node = addNode(job_node, "run_part", "");
224 addNode(run_node, "job_state", job.getState());
225 addNode(run_node, "job_reference", job.getReference());
229 XML_Persistence::createJobFromXmlNode(xmlNodePtr job_node)
231 Launcher::Job * new_job;
234 string job_name = getAttrValue(job_node, "name");
235 if (job_name.empty())
236 throw LauncherException("Invalid job: name is not defined");
237 string job_type = getAttrValue(job_node, "type");
238 if (job_type.empty())
239 throw LauncherException(string("Invalid job \"") + job_name + "\": type is not defined");
240 if (job_type == "command")
241 new_job = new Launcher::Job_Command();
242 else if (job_type == "yacs_file")
243 new_job = new Launcher::Job_YACSFile();
244 else if (job_type == "python_salome")
245 new_job = new Launcher::Job_PythonSALOME();
248 string error = string("Invalid job \"") + job_name + "\": invalid type \"" + job_type + "\"";
249 throw LauncherException(error);
251 new_job->setJobName(job_name);
255 xmlNodePtr current_node = xmlFirstElementChild(job_node);
256 bool user_ok = false;
258 while (current_node != NULL)
260 string node_name = xmlStrToString(current_node->name);
261 if (node_name == "user_part")
263 parseUserNode(new_job, current_node);
266 else if (node_name == "run_part")
268 parseRunNode(new_job, current_node);
272 throw LauncherException(string("invalid node \"") + node_name + "\"");
273 current_node = xmlNextElementSibling(current_node);
275 if (!user_ok) throw LauncherException("missing user part");
276 if (!run_ok) throw LauncherException("missing run part");
278 catch (const LauncherException & exc)
281 string error = string("Invalid job \"") + job_name + "\": " + exc.msg;
282 throw LauncherException(error);
289 XML_Persistence::parseUserNode(Job * new_job, xmlNodePtr user_node)
291 xmlNodePtr current_node = xmlFirstElementChild(user_node);
292 bool job_file_ok = false;
293 while (current_node != NULL)
295 string node_name = xmlStrToString(current_node->name);
296 if (node_name == "job_file")
298 new_job->setJobFile(getNodeContent(current_node));
301 else if (node_name == "env_file")
302 new_job->setEnvFile(getNodeContent(current_node));
303 else if (node_name == "work_directory")
304 new_job->setWorkDirectory(getNodeContent(current_node));
305 else if (node_name == "local_directory")
306 new_job->setLocalDirectory(getNodeContent(current_node));
307 else if (node_name == "result_directory")
308 new_job->setResultDirectory(getNodeContent(current_node));
309 else if (node_name == "launcher_file") // For COORM
310 new_job->setLauncherFile(getNodeContent(current_node));
311 else if (node_name == "launcher_args") // For COORM
312 new_job->setLauncherArgs(getNodeContent(current_node));
313 else if (node_name == "files")
315 // Get in and out files
316 xmlNodePtr file_node = xmlFirstElementChild(current_node);
317 while (file_node != NULL)
319 string file_node_name = xmlStrToString(file_node->name);
320 if (file_node_name == "in_file")
321 new_job->add_in_file(getNodeContent(file_node));
322 else if (file_node_name == "out_file")
323 new_job->add_out_file(getNodeContent(file_node));
325 throw LauncherException(string("invalid node \"") + file_node_name + "\"");
326 file_node = xmlNextElementSibling(file_node);
329 else if (node_name == "resource_params")
330 parseResourceNode(new_job, current_node);
331 else if (node_name == "maximum_duration")
332 new_job->setMaximumDuration(getNodeContent(current_node));
333 else if (node_name == "queue")
334 new_job->setQueue(getNodeContent(current_node));
335 else if (node_name == "exclusive")
336 new_job->setExclusiveStr(getNodeContent(current_node));
337 else if (node_name == "mem_per_cpu")
338 new_job->setMemPerCpu(getNumericalNodeContent<unsigned long>(current_node));
339 else if (node_name == "wckey")
340 new_job->setWCKey(getNodeContent(current_node));
341 else if (node_name == "extra_params")
342 new_job->setExtraParams(getNodeContent(current_node));
343 else if (node_name == "specific_parameters")
345 // Get specific parameters
346 xmlNodePtr parameter_node = xmlFirstElementChild(current_node);
347 while (parameter_node != NULL)
349 string parameter_node_name = xmlStrToString(parameter_node->name);
350 if (parameter_node_name == "specific_parameter")
352 xmlNodePtr inparam_node = xmlFirstElementChild(parameter_node);
355 while (inparam_node != NULL)
357 string inparam_node_name = xmlStrToString(inparam_node->name);
358 if (inparam_node_name == "name")
359 name = getNodeContent(inparam_node);
360 else if (inparam_node_name == "value")
361 value = getNodeContent(inparam_node);
363 throw LauncherException(string("invalid node \"") + inparam_node_name + "\"");
364 inparam_node = xmlNextElementSibling(inparam_node);
366 if (name.empty()) throw LauncherException("missing parameter name");
367 if (value.empty()) throw LauncherException("missing parameter value");
368 new_job->addSpecificParameter(name, value);
371 throw LauncherException(string("invalid node \"") + parameter_node_name + "\"");
372 parameter_node = xmlNextElementSibling(parameter_node);
376 throw LauncherException(string("invalid node \"") + node_name + "\"");
377 current_node = xmlNextElementSibling(current_node);
379 if (!job_file_ok) throw LauncherException("missing job file");
383 XML_Persistence::parseResourceNode(Job * new_job, xmlNodePtr res_node)
386 xmlNodePtr current_node = xmlFirstElementChild(res_node);
387 while (current_node != NULL)
389 string node_name = xmlStrToString(current_node->name);
390 if (node_name == "name")
391 p.name = getNodeContent(current_node);
392 else if (node_name == "hostname")
393 p.hostname = getNodeContent(current_node);
394 else if (node_name == "OS")
395 p.OS = getNodeContent(current_node);
396 else if (node_name == "nb_proc")
397 p.nb_proc = getNumericalNodeContent<long>(current_node);
398 else if (node_name == "nb_node")
399 p.nb_node = getNumericalNodeContent<long>(current_node);
400 else if (node_name == "nb_proc_per_node")
401 p.nb_proc_per_node = getNumericalNodeContent<long>(current_node);
402 else if (node_name == "cpu_clock")
403 p.cpu_clock = getNumericalNodeContent<long>(current_node);
404 else if (node_name == "mem_mb")
405 p.mem_mb = getNumericalNodeContent<long>(current_node);
406 else if (node_name == "mem_per_cpu")
407 new_job->setMemPerCpu(getNumericalNodeContent<long>(current_node));
409 throw LauncherException(string("invalid node \"") + node_name + "\"");
410 current_node = xmlNextElementSibling(current_node);
412 new_job->setResourceRequiredParams(p);
416 XML_Persistence::parseRunNode(Job * new_job, xmlNodePtr run_node)
418 xmlNodePtr current_node = xmlFirstElementChild(run_node);
419 while (current_node != NULL)
421 string node_name = xmlStrToString(current_node->name);
422 if (node_name == "job_state")
423 new_job->setState(getNodeContent(current_node));
424 else if (node_name == "resource_choosed_name")
426 // This parameter was present in older versions of Salome. Now we just silently ignore it.
428 else if (node_name == "job_reference")
429 new_job->setReference(getNodeContent(current_node));
431 throw LauncherException(string("invalid node \"") + node_name + "\"");
432 current_node = xmlNextElementSibling(current_node);
437 XML_Persistence::getAttrValue(xmlNodePtr node, const string & attrName)
440 xmlChar * xmlAttrName = xmlCharStrdup(attrName.c_str());
441 xmlChar * xmlAttrValue = xmlGetProp(node, xmlAttrName);
442 if (xmlAttrValue != NULL) attrValue = (const char *)xmlAttrValue;
443 xmlFree(xmlAttrName);
444 xmlFree(xmlAttrValue);
449 XML_Persistence::xmlStrToString(const xmlChar * xmlStr)
451 return string((const char *)xmlStr);
455 XML_Persistence::getNodeContent(xmlNodePtr node)
458 xmlChar * xmlStrContent = xmlNodeGetContent(node);
459 if (xmlStrContent != NULL) nodeContent = (const char *)xmlStrContent;
460 xmlFree(xmlStrContent);
466 XML_Persistence::getNumericalNodeContent(xmlNodePtr node)
469 istringstream nodeContentStream(getNodeContent(node));
470 if (!(nodeContentStream >> result))
471 throw LauncherException(xmlStrToString(node->name) + " parameter is not correct");
476 XML_Persistence::addNode(xmlNodePtr father, const string & name, const string & content)
478 xmlChar * xmlStrName = xmlCharStrdup(name.c_str());
479 xmlChar * xmlStrContent = NULL;
480 if (!content.empty())
481 xmlStrContent = xmlCharStrdup(content.c_str());
482 xmlNodePtr node = xmlNewChild(father, NULL, xmlStrName, xmlStrContent);
484 xmlFree(xmlStrContent);
490 XML_Persistence::addNumericalNode(xmlNodePtr father, const string & name, T content)
492 ostringstream nodeContentStream;
493 nodeContentStream << content;
494 return addNode(father, name, nodeContentStream.str());
498 XML_Persistence::addAttr(xmlNodePtr node, const string & name, const string & value)
500 xmlChar * xmlStrName = xmlCharStrdup(name.c_str());
501 xmlChar * xmlStrValue = xmlCharStrdup(value.c_str());
502 xmlNewProp(node, xmlStrName, xmlStrValue);
504 xmlFree(xmlStrValue);