Salome HOME
b1458cefa09d695fbee42825de325758d9fa5f9c
[modules/yacs.git] / src / runtime / XMLNode.cxx
1 // Copyright (C) 2006-2020  CEA/DEN, EDF R&D
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 {
57   _implementation=IMPL_NAME;
58   _ref = other._ref;
59 }
60
61 XmlNode::XmlNode(const std::string& name)
62   : ServiceNode(name)
63 {
64   _implementation=IMPL_NAME;
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
93 void XmlNode::execute()
94 {
95   DEBTRACE("execute");
96   char dir[]="yacsXXXXXX";
97   // add a lock around mkdtemp (seems not thread safe)
98   {
99     YACS::BASES::AutoLocker<YACS::BASES::Mutex> alck(&MUTEX);
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