Salome HOME
[EDF29150] : End of save / load of LogManager + non regression test.
[modules/kernel.git] / src / Launcher / SALOME_LogManager.cxx
1 // Copyright (C) 2024  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 "SALOME_LogManager.hxx"
21 #include "SALOME_Fake_NamingService.hxx"
22 #include "SALOME_ContainerManager.hxx"
23
24 #ifndef WIN32
25 #include <unistd.h>
26 #else
27 #include <windows.h>
28 #include <Basics_Utils.hxx>
29 #endif
30
31 #include <sstream>
32 #include <fstream>
33 #include <algorithm>
34 #include <memory>
35 #include <functional>
36
37 const char SALOME_LogManager::NAME_IN_NS[]="/LogManager";
38
39 static std::vector<char> FromPyToCpp(PyObject *obj)
40 {
41   std::vector<char> ret;
42   char *buffer = nullptr;
43   Py_ssize_t length = 0;
44   PyBytes_AsStringAndSize(obj,&buffer,&length);
45   ret.resize(length);
46   for(auto i = 0 ; i < length ; ++i)
47     ret[i] = buffer[i];
48   return ret;
49 }
50
51 static SALOME::vectorOfByte *FromVectCharToCorba(const std::vector<char>& data)
52 {
53   SALOME::vectorOfByte_var ret = new SALOME::vectorOfByte;
54   auto length = data.size();
55   ret->length(length);
56   for(auto i = 0 ; i < length ; ++i)
57     ret[i] = data[i];
58   return ret._retn();
59 }
60
61 PortableServer::POA_var SALOME_ContainerScriptExecPerfLog::getPOA()
62 {
63   return father()->getPOA();
64 }
65
66 void SALOME_ContainerScriptExecPerfLog::assign(const SALOME::vectorOfByte& value)
67 {
68   auto sz = value.length();
69   _data.resize( sz );
70   for(auto i = 0 ; i < sz ; ++i)
71     _data[i] = value[i];
72   //
73   AutoPyRef s( this->end( ) );
74   //
75   _data = FromPyToCpp(s);
76 }
77
78 SALOME::vectorOfByte *SALOME_ContainerScriptExecPerfLog::getObj()
79 {
80   return FromVectCharToCorba(this->_data);
81 }
82
83 void SALOME_ContainerScriptExecPerfLog::accept(SALOME_VisitorContainerLog &visitor)
84 {
85   visitor.visitContainerScriptExecPerfLog( *this );
86 }
87
88 void SALOME_ContainerScriptExecPerfLog::start()
89 {
90   AutoGIL gstate;
91   AutoPyRef result = PyObject_CallMethod(pyObj(),(char*)"start","",nullptr);
92   if (PyErr_Occurred())
93   {
94     std::string error("can not start");
95     PyErr_Print();
96     THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
97   }
98 }
99
100 AutoPyRef SALOME_ContainerScriptExecPerfLog::end()
101 {
102   AutoGIL gstate;
103   //https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue
104   AutoPyRef result(PyObject_CallMethod(pyObj(),(char*)"end","y#",_data.data(),_data.size(),nullptr) ) ;
105   if (PyErr_Occurred())
106   {
107     std::string error("can not end");
108     PyErr_Print();
109     THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
110   }
111   return result;
112 }
113
114 /////
115
116 PortableServer::POA_var SALOME_ContainerScriptPerfLog::getPOA()
117 {
118   return father()->getPOA();
119 }
120
121 char *SALOME_ContainerScriptPerfLog::getCode()
122 {
123   return CORBA::string_dup( _code.c_str() );
124 }
125
126 char *SALOME_ContainerScriptPerfLog::getName()
127 {
128   return CORBA::string_dup( _name.c_str() );
129 }
130
131 void SALOME_ContainerScriptPerfLog::accept(SALOME_VisitorContainerLog &visitor)
132 {
133   visitor.enterContainerScriptPerfLog( *this );
134   for(auto session : _sessions)
135   {
136     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( session );
137     serv->_remove_ref();
138     SALOME_ContainerScriptExecPerfLog *servC = dynamic_cast<SALOME_ContainerScriptExecPerfLog *>(serv);
139     visitor.visitContainerScriptExecPerfLog( *servC );
140   }
141   visitor.leaveContainerScriptPerfLog( *this );
142 }
143
144 Engines::ContainerScriptExecPerfLog_ptr SALOME_ContainerScriptPerfLog::addExecutionSession()
145 {
146   SALOME_ContainerScriptExecPerfLog *execution = new SALOME_ContainerScriptExecPerfLog(this);
147   PortableServer::ObjectId_var id(getPOA()->activate_object(execution));
148   execution->_remove_ref();
149   CORBA::Object_var executionPtr(getPOA()->id_to_reference(id));
150   Engines::ContainerScriptExecPerfLog_var executionPtr2 = Engines::ContainerScriptExecPerfLog::_narrow(executionPtr);
151   _sessions.push_back( executionPtr2 );
152   {
153     AutoGIL gstate;
154     AutoPyRef result = PyObject_CallMethod(pyObj(),(char*)"addExecution","",nullptr);
155     if (PyErr_Occurred())
156     {
157       std::string error("can not addExecution");
158       PyErr_Print();
159       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
160     }
161     execution->setPyObj( result.retn() );//ownership of result is transfered to execution
162   }
163   execution->start();
164   return executionPtr2._retn();
165 }
166
167 Engines::ListOfContainerScriptExecPerfLog *SALOME_ContainerScriptPerfLog::listOfExecs()
168 {
169   Engines::ListOfContainerScriptExecPerfLog_var ret = new Engines::ListOfContainerScriptExecPerfLog;
170   auto sz = this->_sessions.size();
171   ret->length(sz);
172   for(auto i = 0 ; i < sz ; ++i)
173     ret[i] = this->_sessions[i];
174   return ret._retn();
175 }
176
177 /////
178
179 PortableServer::POA_var SALOME_ContainerPerfLog::getPOA()
180 {
181   return father()->getPOA();
182   }
183
184 Engines::ContainerScriptPerfLog_ptr SALOME_ContainerPerfLog::addScript(const char *name, const char *code)
185 {
186   SALOME_ContainerScriptPerfLog *script = new SALOME_ContainerScriptPerfLog(this,name,code);
187   PortableServer::ObjectId_var id(getPOA()->activate_object(script));
188   script->_remove_ref();
189   CORBA::Object_var scriptPtr(getPOA()->id_to_reference(id));
190   Engines::ContainerScriptPerfLog_var scriptPtr2 = Engines::ContainerScriptPerfLog::_narrow(scriptPtr);
191   _scripts.push_back( scriptPtr2 );
192   {
193     AutoGIL gstate;
194     PyObject *result = PyObject_CallMethod(pyObj(),(char*)"addScript","",nullptr);
195     if (PyErr_Occurred())
196     {
197       std::string error("can not addScript");
198       PyErr_Print();
199       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
200     }
201     script->setPyObj( result );
202   }
203   return scriptPtr2._retn();
204 }
205
206 Engines::ListOfContainerScriptPerfLog *SALOME_ContainerPerfLog::listOfScripts()
207 {
208   Engines::ListOfContainerScriptPerfLog_var ret = new Engines::ListOfContainerScriptPerfLog;
209   std::size_t len( this->_scripts.size() );
210   ret->length( len );
211   for(std::size_t i = 0 ; i < len ; ++i)
212     ret[i] = this->_scripts[i];
213   return ret._retn();
214 }
215
216 void SALOME_ContainerPerfLog::accept(SALOME_VisitorContainerLog &visitor)
217 {
218   visitor.enterContainerPerfLog( *this );
219   for(auto script : _scripts)
220   {
221     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( script );
222     serv->_remove_ref();
223     SALOME_ContainerScriptPerfLog *servC = dynamic_cast<SALOME_ContainerScriptPerfLog *>(serv);
224     servC->accept(visitor);
225   }
226   visitor.leaveContainerPerfLog( *this );
227 }
228
229 char *SALOME_ContainerPerfLog::getLogFile()
230 {
231   return CORBA::string_dup( this->_log_file.c_str() );
232 }
233
234 char *SALOME_ContainerPerfLog::getContainerEntryInNS()
235 {
236   return CORBA::string_dup( this->_name_in_ns.c_str() );
237 }
238
239 /////
240
241 SALOME_LogManager::SALOME_LogManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa,SALOME_NamingService_Abstract *ns):_poa(poa)
242 {
243   _NS.reset(ns);
244   PortableServer::ObjectId_var id(_poa->activate_object(this));
245   CORBA::Object_var obj(_poa->id_to_reference(id));
246   Engines::LogManager_var refPtr(Engines::LogManager::_narrow(obj));
247   _NS->Register(refPtr,NAME_IN_NS);
248   {
249     AutoGIL gstate;
250     std::ostringstream myCommand;
251     myCommand << "mylogmanager = SALOME_LogManager.SALOME_LogManagerHelper()";
252     PyRun_SimpleString("import SALOME_LogManager");
253     PyRun_SimpleString((char*)myCommand.str().c_str());
254     PyObject *mainmod = PyImport_AddModule("__main__");
255     PyObject *globals = PyModule_GetDict(mainmod);
256     _pyLogManager = PyDict_GetItemString(globals, "mylogmanager");
257   }
258 }
259
260 Engines::ContainerPerfLog_ptr SALOME_LogManager::declareContainer(const char *contInNS, const char *logfile)
261 {
262   SALOME_ContainerPerfLog *cont = new SALOME_ContainerPerfLog(this,contInNS,logfile);
263   PortableServer::ObjectId_var id(_poa->activate_object(cont));
264   CORBA::Object_var contPtr(_poa->id_to_reference(id));
265   cont->_remove_ref();
266   Engines::ContainerPerfLog_var contPtr2 = Engines::ContainerPerfLog::_narrow(contPtr);
267   _containers.push_back( contPtr2 );
268   {
269     AutoGIL gstate;
270     PyObject *result = PyObject_CallMethod(_pyLogManager,(char*)"declareContainer","ss",contInNS,logfile,nullptr);
271     if (PyErr_Occurred())
272     {
273       std::string error("can not declareContainer");
274       PyErr_Print();
275       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
276     }
277     cont->setPyObj( result );
278   }
279   return contPtr2._retn();
280 }
281
282 Engines::ListOfContainerPerfLog *SALOME_LogManager::listOfContainerLogs()
283 {
284   Engines::ListOfContainerPerfLog_var ret = new Engines::ListOfContainerPerfLog;
285   std::size_t len( this->_containers.size() );
286   ret->length( len );
287   for(std::size_t i = 0 ; i < len ; ++i)
288   {
289     ret[i] = this->_containers[i];
290   }
291   return ret._retn();
292 }
293
294 void SALOME_LogManager::accept(SALOME_VisitorContainerLog &visitor)
295 {
296   visitor.enterLogManager( *this );
297   for(auto container : _containers)
298   {
299     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( container );
300     serv->_remove_ref();
301     SALOME_ContainerPerfLog *servC = dynamic_cast<SALOME_ContainerPerfLog *>(serv);
302     servC->accept(visitor);
303   }
304   visitor.leaveLogManager( *this );
305 }
306
307 /*!
308   \param [in] unloadMemory - specify if big part of struct data (SALOME_ContainerScriptExecPerfLog) is cleared after retrieving data
309  */
310 SALOME::vectorOfByte *SALOME_LogManager::getAllStruct(bool clearMemory)
311 {
312   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
313   return FromVectCharToCorba(data);
314 }
315
316 ///////////////////////
317  
318  #include <cstdint>
319
320 static void PushIntInVC(std::uint32_t val, std::vector<char>& data)
321 {
322   char *valPtr = reinterpret_cast<char *>(&val);
323   data.insert(data.end(),valPtr,valPtr+sizeof(std::uint32_t));
324 }
325  
326 template<class T>
327 static void PushStringInVC(const T& str, std::vector<char>& data)
328 {
329   std::uint32_t sz = static_cast<std::uint32_t>( str.size() );
330   PushIntInVC(sz,data);
331   data.insert(data.end(),str.data(),str.data()+sz);
332 }
333
334 class InternalFormatVisitorDump : public SALOME_VisitorContainerLog
335 {
336 public:
337   InternalFormatVisitorDump(bool clearMemory, std::vector<char> *data):_clear_memory(clearMemory),_data(data) { }
338   void enterLogManager(SALOME_LogManager& inst) override;
339   void leaveLogManager(SALOME_LogManager& inst) override { }
340   void enterContainerPerfLog(SALOME_ContainerPerfLog& inst) override;
341   void leaveContainerPerfLog(SALOME_ContainerPerfLog& inst) override { }
342   void enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override;
343   void leaveContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override { }
344   void visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst) override;
345 private:
346   bool _clear_memory = false;
347   std::vector<char> *_data = nullptr;
348 };
349
350 void InternalFormatVisitorDump::visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst)
351 {
352   PushStringInVC<std::vector<char>>(inst.data(),*_data);
353   if( _clear_memory )
354     inst.clear();
355 }
356
357 void InternalFormatVisitorDump::enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst)
358 {
359   PushStringInVC<std::string>(inst.name(),*_data);
360   PushStringInVC<std::string>(inst.code(),*_data);
361   PushIntInVC((std::uint32_t)inst.getNumberOfSessions(),*_data);
362 }
363
364 void InternalFormatVisitorDump::enterContainerPerfLog(SALOME_ContainerPerfLog& inst)
365 {
366   PushStringInVC<std::string>(inst.nameInNS(),*_data);
367   PushStringInVC<std::string>(inst.logFile(),*_data);
368   PushIntInVC((std::uint32_t)inst.getNumberOfScripts(),*_data);
369 }
370
371 void InternalFormatVisitorDump::enterLogManager(SALOME_LogManager& inst)
372 {
373   PushIntInVC((std::uint32_t)inst.getNumberOfContainers(),*_data);
374 }
375
376 std::vector<char> SALOME_LogManager::dumpCppInternalFrmt(bool clearMemory)
377 {
378   std::vector<char> ret;
379   InternalFormatVisitorDump visitor(clearMemory,&ret);
380   this->accept( visitor );
381   return ret;
382 }