Version: 9.15.0
XMLNode.cxx
Go to the documentation of this file.
1 // Copyright (C) 2006-2025 CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 
20 #include "XMLNode.hxx"
21 #include "XMLPorts.hxx"
22 #include "Mutex.hxx"
23 #include "TypeCode.hxx"
24 #include "AutoLocker.hxx"
25 
26 #include <libxml/parser.h>
27 #include <libxml/tree.h>
28 
29 #include <stdlib.h>
30 #include <iostream>
31 #include <fstream>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 
35 #ifdef WIN32
36 #include <windows.h>
37 #include <io.h>
38 #define chmod _chmod
39 #endif
40 #ifdef __APPLE__
41 #include <unistd.h> // for mkdtemp
42 #endif
43 
44 //#define _DEVDEBUG_
45 #include "YacsTrace.hxx"
46 
47 using namespace YACS::ENGINE;
48 using namespace std;
49 
50 const char XmlNode::IMPL_NAME[]="XML";
51 const char XmlNode::KIND[]="xmlsh";
52 static YACS::BASES::Mutex MUTEX;
53 
54 XmlNode::XmlNode(const XmlNode& other, ComposedNode *father)
55  : _script(other._script), ServiceNode(other, father)
56 {
58  _ref = other._ref;
59 }
60 
61 XmlNode::XmlNode(const std::string& name)
62  : ServiceNode(name)
63 {
65 }
66 
67 Node *XmlNode::simpleClone(ComposedNode *father, bool editionOnly) const
68 {
69  return new XmlNode(*this,father);
70 }
71 
72 void XmlNode::setRef(const std::string& ref)
73 {
74  //No component instance here
75  _ref=ref;
76 }
77 
78 void XmlNode::setScript(const std::string& script)
79 {
80  _script=script;
81 }
82 
83 std::string XmlNode::getScript() const
84 {
85  return _script;
86 }
87 
88 std::string XmlNode::getKind() const
89 {
90  return KIND;
91 }
92 
94 {
95  DEBTRACE("execute");
96  char dir[]="yacsXXXXXX";
97  // add a lock around mkdtemp (seems not thread safe)
98  {
100 #ifdef WIN32
101 #ifdef UNICODE
102 wchar_t mdir[512 + 1];
103 #else
104  char mdir[512 + 1];
105 #endif
106  GetTempPath(MAX_PATH+1, mdir);
107  CreateDirectory(mdir, NULL);
108 #else
109  char* mdir=mkdtemp(dir);
110 #endif
111  if(mdir==NULL)
112  {
113  perror("mkdtemp failed");
114  std::cerr << "Problem in mkdtemp " << dir << " " << mdir << std::endl;
115  throw Exception("Execution problem in mkdtemp");
116  }
117  }
118  std::string sdir(dir);
119  std::string input=sdir+"/input";
120  std::ofstream f(input.c_str());
121  f<<"<methodCall> <methodName>" << _method << "</methodName> <params>"<<std::endl;
122  DEBTRACE("---------------XmlNode::inputs---------------");
123  list<InputPort *>::iterator iter;
124  for(iter = _setOfInputPort.begin(); iter != _setOfInputPort.end(); iter++)
125  {
126  InputXmlPort *p=(InputXmlPort *)*iter;
127  DEBTRACE("port name: " << p->getName());
128  DEBTRACE("port kind: " << p->edGetType()->kind());
129  const char* ob=p->getXml();
130  DEBTRACE("Xml: " << ob );
131  f<<"<param>" << ob << "</param>"<<std::endl;
132  }
133  f<<"</params>"<<std::endl;
134  f<<"</methodCall>"<<std::endl;
135  f.close();
136  DEBTRACE("--------------XmlNode::calculation---------------" << _ref );
137  std::string call=sdir+"/run.sh";
138  std::ofstream run(call.c_str());
139  run << "#!/bin/sh" << std::endl;
140  run << "cd " << sdir << std::endl;
141  if(_ref[0]=='/' || _ref[0]=='~')
142  run << _ref << "> stdout 2>&1 " << std::endl;
143  else
144  run << "../"<<_ref << "> stdout 2>&1 " << std::endl;
145  //run << "cat stdout" << std::endl;
146  run.close();
147  chmod(call.c_str(),00777);
148 
149  std::string call2="/bin/sh "+call;
150  int ret=system(call2.c_str());
151  if(ret)
152  {
153  std::cerr << "Problem: " << ret << std::endl;
154  DEBTRACE("Problem: " << ret);
155  throw Exception("Execution problem");
156  }
157  std::string output=sdir+"/output";
158  xmlDocPtr doc;
159  doc = xmlReadFile(output.c_str(), NULL, 0);
160  if (doc == NULL)
161  {
162  DEBTRACE("Failed to parse " << output);
163  throw Exception("Execution problem");
164  }
165  xmlNodePtr cur;
166  cur = xmlDocGetRootElement(doc);
167  if (cur == NULL)
168  {
169  DEBTRACE("empty document " );
170  xmlFreeDoc(doc);
171  throw Exception("Execution problem");
172  }
173  if (xmlStrcmp(cur->name, (const xmlChar *) "methodResponse"))
174  {
175  DEBTRACE("document of the wrong type, root node != methodResponse");
176  xmlFreeDoc(doc);
177  throw Exception("Execution problem");
178  }
179  cur = cur->xmlChildrenNode;
180  xmlBufferPtr buf=xmlBufferCreate();
181  list<OutputPort *>::iterator iter2;
182  iter2 = _setOfOutputPort.begin();
183  OutputXmlPort *p;
184  p=(OutputXmlPort *)*iter2;
185  int nres=0;
186 
187  while (cur != NULL)
188  {
189  if ((!xmlStrcmp(cur->name, (const xmlChar *)"fault")))
190  {
191  DEBTRACE("exception in shell" );
192  xmlFreeDoc(doc);
193  throw Exception("Execution problem");
194  }
195  if ((!xmlStrcmp(cur->name, (const xmlChar *)"params")))
196  {
197  xmlNodePtr cur0 = cur->xmlChildrenNode;
198  while (cur0 != NULL)
199  {
200  if ((!xmlStrcmp(cur0->name, (const xmlChar *)"param")))
201  {
202  xmlNodePtr cur1 = cur0->xmlChildrenNode;
203  while (cur1 != NULL)
204  {
205  if ((!xmlStrcmp(cur1->name, (const xmlChar *)"value")))
206  {
207  xmlNodePtr cur2=cur1->xmlChildrenNode;
208  while (cur2 != NULL)
209  {
210  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"int")))
211  {
212  //got an int
213  if(getNumberOfOutputPorts()!=1)
214  {
215  //mismatch
216  xmlBufferFree(buf);
217  xmlFreeDoc(doc);
218  throw Exception("Execution problem:mismatch in output numbers");
219  }
220  xmlBufferEmpty(buf);
221  xmlNodeDump(buf,doc,cur1,0,0);
222  DEBTRACE(xmlBufferContent(buf));
223  p->put(xmlBufferContent(buf));
224  }
225  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"double")))
226  {
227  //got an double
228  if(getNumberOfOutputPorts()!=1)
229  {
230  //mismatch
231  xmlBufferFree(buf);
232  xmlFreeDoc(doc);
233  throw Exception("Execution problem:mismatch in output numbers");
234  }
235  xmlBufferEmpty(buf);
236  xmlNodeDump(buf,doc,cur1,0,0);
237  DEBTRACE(xmlBufferContent(buf));
238  p->put(xmlBufferContent(buf));
239  }
240  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"string")))
241  {
242  //got an string
243  if(getNumberOfOutputPorts()!=1)
244  {
245  //mismatch
246  xmlBufferFree(buf);
247  xmlFreeDoc(doc);
248  throw Exception("Execution problem:mismatch in output port numbers");
249  }
250  xmlBufferEmpty(buf);
251  xmlNodeDump(buf,doc,cur1,0,0);
252  DEBTRACE(xmlBufferContent(buf));
253  p->put(xmlBufferContent(buf));
254  }
255  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"boolean")))
256  {
257  //got an boolean
258  if(getNumberOfOutputPorts()!=1)
259  {
260  //mismatch
261  xmlBufferFree(buf);
262  xmlFreeDoc(doc);
263  throw Exception("Execution problem:mismatch in output port numbers");
264  }
265  xmlBufferEmpty(buf);
266  xmlNodeDump(buf,doc,cur1,0,0);
267  DEBTRACE(xmlBufferContent(buf));
268  p->put(xmlBufferContent(buf));
269  }
270  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"objref")))
271  {
272  //got an objref
273  if(getNumberOfOutputPorts()!=1)
274  {
275  //mismatch
276  xmlBufferFree(buf);
277  xmlFreeDoc(doc);
278  throw Exception("Execution problem:mismatch in output port numbers");
279  }
280  xmlBufferEmpty(buf);
281  xmlNodeDump(buf,doc,cur1,0,0);
282  DEBTRACE(xmlBufferContent(buf));
283  p->put(xmlBufferContent(buf));
284  }
285  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"struct")))
286  {
287  //got an struct
288  if(getNumberOfOutputPorts()!=1)
289  {
290  //mismatch
291  xmlBufferFree(buf);
292  xmlFreeDoc(doc);
293  throw Exception("Execution problem:mismatch in output port numbers");
294  }
295  xmlBufferEmpty(buf);
296  xmlNodeDump(buf,doc,cur1,0,0);
297  DEBTRACE(xmlBufferContent(buf));
298  p->put(xmlBufferContent(buf));
299  }
300  if ((!xmlStrcmp(cur2->name, (const xmlChar *)"array")))
301  {
302  //got a tuple of results or only one result (but a list)
303  if(getNumberOfOutputPorts()==1)
304  {
305  //It's a one result list
306  xmlBufferEmpty(buf);
307  xmlNodeDump(buf,doc,cur1,0,0);
308  DEBTRACE(xmlBufferContent(buf));
309  p->put(xmlBufferContent(buf));
310  }
311  else
312  {
313  //It's a list of results
314  xmlNodePtr cur3=cur2->xmlChildrenNode;
315  while (cur3 != NULL)
316  {
317  if ((!xmlStrcmp(cur3->name, (const xmlChar *)"data")))
318  {
319  xmlNodePtr cur4=cur3->xmlChildrenNode;
320  while (cur4 != NULL)
321  {
322  if ((!xmlStrcmp(cur4->name, (const xmlChar *)"value")))
323  {
324  nres++;
325  if(nres > getNumberOfOutputPorts())
326  {
327  //mismatch
328  xmlBufferFree(buf);
329  xmlFreeDoc(doc);
330  throw Exception("Execution problem:mismatch in output port numbers");
331  }
332  xmlBufferEmpty(buf);
333  xmlNodeDump(buf,doc,cur4,0,0);
334  DEBTRACE(xmlBufferContent(buf));
335  p=(OutputXmlPort *)*iter2;
336  p->put(xmlBufferContent(buf));
337  iter2++;
338  }
339  cur4 = cur4->next;
340  } // end while value
341  break;
342  }
343  cur3 = cur3->next;
344  } // end while data
345  }
346  break;
347  }
348  cur2 = cur2->next;
349  } // end while array
350  break;
351  }
352  cur1 = cur1->next;
353  } // end while value
354  }
355  cur0 = cur0->next;
356  }// end while param
357  }
358  cur = cur->next;
359  }
360  xmlBufferFree(buf);
361  xmlFreeDoc(doc);
362 }
363 
364 
static YACS::BASES::Mutex MUTEX
Definition: XMLNode.cxx:52
#define DEBTRACE(msg)
Definition: YacsTrace.hxx:31
Base class for all composed nodes.
std::string getName() const
std::list< InputPort * > _setOfInputPort
std::list< OutputPort * > _setOfOutputPort
Class for XML Input Ports.
Definition: XMLPorts.hxx:38
Base class for all nodes.
Definition: Node.hxx:70
std::string _implementation
Definition: Node.hxx:97
Class for XML Output Ports.
Definition: XMLPorts.hxx:68
Class for calculation node associated with a component service.
Definition: ServiceNode.hxx:35
virtual std::string getScript() const
Definition: XMLNode.cxx:83
Node * simpleClone(ComposedNode *father, bool editionOnly) const
Definition: XMLNode.cxx:67
virtual void execute()
Definition: XMLNode.cxx:93
virtual std::string getKind() const
Return the service node kind.
Definition: XMLNode.cxx:88
virtual void setScript(const std::string &script)
Definition: XMLNode.cxx:78
XmlNode(const XmlNode &other, ComposedNode *father)
Definition: XMLNode.cxx:54
static const char IMPL_NAME[]
Definition: XMLNode.hxx:46
virtual void setRef(const std::string &ref)
Associate a new component instance to this service node.
Definition: XMLNode.cxx:72
static const char KIND[]
Definition: XMLNode.hxx:47
std::string _script
Definition: XMLNode.hxx:49
Proc * p
Definition: driver.cxx:216
static char doc[]
Definition: driver.cxx:63
def ref(target, callback=None)
Definition: CONNECTOR.py:120
void * run(void *obj)
Definition: yacs_clt.cxx:54