Salome HOME
Copyright update 2020
[modules/kernel.git] / src / DSC / DSC_Basic / DSC_interface.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  File   : DSC_interface.cxx
24 //  Author : AndrĂ© RIBES (EDF)
25 //  Module : KERNEL
26 //
27 #include <string>
28 #include "DSC_interface.hxx"
29 #ifdef WIN32
30 #else
31 #include <sys/time.h>
32 #endif
33 #include <fstream>
34 #include <sys/stat.h>
35 #include <sstream>
36 #include <stdlib.h>
37
38 //#define MYDEBUG
39
40 Engines_DSC_interface::Engines_DSC_interface() {}
41
42 Engines_DSC_interface::~Engines_DSC_interface() 
43 {
44   my_ports_it = my_ports.begin();
45   for(;my_ports_it != my_ports.end();my_ports_it++)
46     delete my_ports_it->second;
47
48 }
49
50 void
51 Engines_DSC_interface::add_provides_port(Ports::Port_ptr ref, 
52                                  const char* provides_port_name,
53                                  Ports::PortProperties_ptr port_prop) 
54 throw (Engines::DSC::PortAlreadyDefined,
55        Engines::DSC::NilPort,
56        Engines::DSC::BadProperty) 
57 {
58   // Method args test
59   assert(provides_port_name);
60   if (CORBA::is_nil(ref))
61     throw Engines::DSC::NilPort();
62   if (CORBA::is_nil(port_prop))
63     throw Engines::DSC::BadProperty();
64
65   my_ports_it = my_ports.find(provides_port_name);
66   if (my_ports_it ==  my_ports.end()) {
67     // Creating a new port provides
68     port_t * new_port = new port_t();
69     new_port->type = provides;
70     new_port->connection_nbr = 0;
71     new_port->provides_port_ref = Ports::Port::_duplicate(ref);
72     new_port->port_prop = Ports::PortProperties::_duplicate(port_prop);
73
74     // Port into the port's map
75     my_ports[provides_port_name] = new_port;
76   }
77   else
78     throw Engines::DSC::PortAlreadyDefined();
79 }
80
81 void
82 Engines_DSC_interface::add_uses_port(const char* repository_id, 
83                              const char* uses_port_name,
84                              Ports::PortProperties_ptr port_prop) 
85 throw (Engines::DSC::PortAlreadyDefined,
86        Engines::DSC::BadProperty) 
87 {
88   // Method args test
89   // Note : We can't be shure that repository id
90   // is a correct CORBA id.
91   assert(repository_id);
92   assert(uses_port_name);
93   if (CORBA::is_nil(port_prop))
94     throw Engines::DSC::BadProperty();
95
96   my_ports_it = my_ports.find(uses_port_name);
97   if (my_ports_it ==  my_ports.end()) {
98     // Creating a new uses port
99     port_t * new_port = new port_t();
100     new_port->type = uses;
101     new_port->connection_nbr = 0;
102     new_port->uses_port_refs.length(0);
103     new_port->repository_id = repository_id;
104     new_port->port_prop = Ports::PortProperties::_duplicate(port_prop);
105
106     // Port into port's map
107     my_ports[uses_port_name] = new_port;
108   }
109   else
110     throw Engines::DSC::PortAlreadyDefined();
111 }
112
113 Ports::Port_ptr
114 Engines_DSC_interface::get_provides_port(const char* provides_port_name,
115                                  const CORBA::Boolean connection_error) 
116   throw (Engines::DSC::PortNotDefined,
117          Engines::DSC::PortNotConnected, 
118          Engines::DSC::BadPortType) 
119 {
120   // Method arg test
121   assert(provides_port_name);
122
123   Ports::Port_ptr rtn_port = Ports::Port::_nil();
124 //   std::cout << "---- DSC_Interface : MARK 1 ---- Recherche de : " << provides_port_name << "----" << std::endl;
125 //   ports::iterator it;
126 //   std::cout << "----> ";
127 //   for(it=my_ports.begin();it!=my_ports.end();++it) 
128 //     std::cout << "|"<<(*it).first<<"|, ";
129 //   std::cout << std::endl;
130  
131   // Searching the port
132   my_ports_it = my_ports.find(provides_port_name);
133   if (my_ports_it ==  my_ports.end())
134     throw Engines::DSC::PortNotDefined();
135   if (my_ports[provides_port_name]->type != provides) {
136     Engines::DSC::BadPortType BPT;
137     BPT.expected = CORBA::string_dup("Expected a provides port");
138     BPT.received = CORBA::string_dup((std::string("Received a uses/none port : ")+provides_port_name).c_str());
139     throw BPT;
140   }
141
142   if (my_ports[provides_port_name]->connection_nbr == 0 && connection_error)
143     throw Engines::DSC::PortNotConnected();
144
145   rtn_port = Ports::Port::_duplicate(my_ports[provides_port_name]->provides_port_ref);
146   return rtn_port;
147 }
148
149 Engines::DSC::uses_port * 
150 Engines_DSC_interface::get_uses_port(const char* uses_port_name) 
151   throw (Engines::DSC::PortNotDefined,
152          Engines::DSC::PortNotConnected,
153          Engines::DSC::BadPortType) 
154 {
155   // Method arg test
156   assert(uses_port_name);
157
158   Engines::DSC::uses_port * rtn_port = NULL;  
159
160   // Searching the uses port
161   my_ports_it = my_ports.find(uses_port_name);
162   if (my_ports_it == my_ports.end())
163     throw Engines::DSC::PortNotDefined();
164   if (my_ports[uses_port_name]->type != uses){
165     Engines::DSC::BadPortType BPT;
166     BPT.expected = CORBA::string_dup("Expected a uses port");
167     BPT.received = CORBA::string_dup((std::string("Received a provides/none port : ")+uses_port_name).c_str());
168 #ifdef MYDEBUG
169    std::cout << "---- DSC_Interface : MARK 1 ---- exception : " << uses_port_name << "----" << std::endl;
170 #endif
171     throw BPT;
172   }
173
174   // Is the port connected ?
175   if (my_ports[uses_port_name]->connection_nbr > 0) {
176     rtn_port = new Engines::DSC::uses_port(my_ports[uses_port_name]->uses_port_refs);
177   }
178   else
179     {
180 #ifdef MYDEBUG
181    std::cout << "---- DSC_Interface : MARK 2 ---- exception : " << uses_port_name << "----" << std::endl;
182 #endif
183     throw Engines::DSC::PortNotConnected();
184     }
185   
186   return rtn_port;
187 }
188
189 void
190 Engines_DSC_interface::connect_provides_port(const char* provides_port_name)
191     throw (Engines::DSC::PortNotDefined)
192 {
193   // Method arg test
194   assert(provides_port_name);
195
196   // Searching the provides port
197   my_ports_it = my_ports.find(provides_port_name);
198   if (my_ports_it ==  my_ports.end())
199     throw Engines::DSC::PortNotDefined();
200   if (my_ports[provides_port_name]->type != provides)
201     throw Engines::DSC::PortNotDefined();
202
203
204   // Adding a new connection
205   my_ports[provides_port_name]->connection_nbr += 1;
206   // User code is informed
207   provides_port_changed(provides_port_name, 
208                         my_ports[provides_port_name]->connection_nbr,
209                         Engines::DSC::AddingConnection
210                        );
211 }
212
213 void
214 Engines_DSC_interface::connect_uses_port(const char* uses_port_name,
215                                          Ports::Port_ptr provides_port_ref) 
216   throw (Engines::DSC::PortNotDefined,
217          Engines::DSC::BadPortType,
218          Engines::DSC::NilPort)
219 {
220   // Method arg test
221   assert(uses_port_name);
222
223   if (CORBA::is_nil(provides_port_ref))
224     throw Engines::DSC::NilPort();
225
226   // Searching the uses port
227   my_ports_it = my_ports.find(uses_port_name);
228   if (my_ports_it ==  my_ports.end())
229     throw Engines::DSC::PortNotDefined();
230   if (my_ports[uses_port_name]->type != uses) {
231     Engines::DSC::BadPortType BPT;
232     BPT.expected = CORBA::string_dup("Expected a uses port");
233     BPT.received = CORBA::string_dup((std::string("Received a provides/none port : ")+uses_port_name).c_str());
234     throw BPT;
235   }
236
237   // repository_id test
238   const char * repository_id = my_ports[uses_port_name]->repository_id.c_str();
239   if (provides_port_ref->_is_a(repository_id)) 
240   {
241     // Adding provides port into the uses port sequence
242     CORBA::ULong lgth = my_ports[uses_port_name]->uses_port_refs.length();
243     my_ports[uses_port_name]->
244       uses_port_refs.length(lgth + 1);
245     my_ports[uses_port_name]->uses_port_refs[lgth] = 
246       Ports::Port::_duplicate(provides_port_ref);
247
248     // Adding a new connection
249     my_ports[uses_port_name]->connection_nbr += 1;
250     // User code is informed
251     uses_port_changed(uses_port_name,
252                       new Engines::DSC::uses_port(my_ports[uses_port_name]->uses_port_refs),
253                       Engines::DSC::AddingConnection);
254   }
255   else {
256     Engines::DSC::BadPortType BPT;
257     BPT.expected = CORBA::string_dup("Expected ...");
258     BPT.received = CORBA::string_dup((std::string("Received an incorrect repository id type ")+
259                                       repository_id).c_str());
260     throw BPT;
261   }
262
263 }
264
265 CORBA::Boolean
266 Engines_DSC_interface::is_connected(const char* port_name) 
267   throw (Engines::DSC::PortNotDefined) 
268 {
269   CORBA::Boolean rtn = false;
270
271   // Method arg test
272   assert(port_name);
273
274   my_ports_it = my_ports.find(port_name);
275   if (my_ports_it ==  my_ports.end())
276     throw Engines::DSC::PortNotDefined();
277
278   // Is it connected ?
279   if (my_ports[port_name]->connection_nbr > 0)
280     rtn = true;
281
282   return rtn;
283 }
284
285 void
286 Engines_DSC_interface::disconnect_provides_port(const char* provides_port_name,
287                                         const Engines::DSC::Message message)
288 throw (Engines::DSC::PortNotDefined,
289        Engines::DSC::PortNotConnected)
290 {
291   // Method args test
292   assert(provides_port_name);
293
294   my_ports_it = my_ports.find(provides_port_name);
295   if (my_ports_it ==  my_ports.end())
296     throw Engines::DSC::PortNotDefined();
297   if (my_ports[provides_port_name]->type != provides)
298     throw Engines::DSC::PortNotDefined();
299
300   // Is it connected ?
301   if (my_ports[provides_port_name]->connection_nbr > 0) 
302   {
303     my_ports[provides_port_name]->connection_nbr -= 1;
304     provides_port_changed(provides_port_name,
305                           my_ports[provides_port_name]->connection_nbr,
306                           message);
307   }
308   else
309     throw Engines::DSC::PortNotConnected();
310 }
311
312 void
313 Engines_DSC_interface::disconnect_uses_port(const char* uses_port_name,
314                                     Ports::Port_ptr provides_port_ref,
315                                     const Engines::DSC::Message message)
316 throw (Engines::DSC::PortNotDefined,
317        Engines::DSC::PortNotConnected,
318        Engines::DSC::BadPortReference) 
319 {
320   // Method args test
321   assert(uses_port_name);
322
323   my_ports_it = my_ports.find(uses_port_name);
324   if (my_ports_it ==  my_ports.end())
325     throw Engines::DSC::PortNotDefined();
326   if (my_ports[uses_port_name]->type != uses)
327     throw Engines::DSC::PortNotDefined();
328
329   if (CORBA::is_nil(provides_port_ref))
330     throw Engines::DSC::BadPortReference();
331
332   // Is it connected ?
333   if (my_ports[uses_port_name]->connection_nbr > 0) {
334     CORBA::Long port_index = -1;
335     CORBA::ULong seq_length = my_ports[uses_port_name]->uses_port_refs.length(); 
336     for(int i = 0; i < seq_length; i++)
337     {
338       if (my_ports[uses_port_name]->uses_port_refs[i]->_is_equivalent(provides_port_ref))
339       {
340         port_index = i;
341         break;
342       }
343     }
344     if (port_index == -1)
345       throw Engines::DSC::BadPortReference();
346
347     my_ports[uses_port_name]->connection_nbr -= 1;
348     Engines::DSC::uses_port * new_uses_port = 
349       new Engines::DSC::uses_port();
350     new_uses_port->length(seq_length - 1);
351
352     int index_ancien = 0;
353     int index_nouveau = 0;
354     for(;index_ancien < seq_length;) {
355       if (index_ancien == port_index) 
356       {
357         // Rien a faire !
358         // On ne change pas le index du nouveau tableau
359         index_ancien += 1;
360       }
361       else 
362       {
363         (*new_uses_port)[index_nouveau] = my_ports[uses_port_name]->uses_port_refs[index_ancien];
364         index_ancien += 1;
365         index_nouveau += 1;
366       }
367     }
368
369     // New uses port's sequence
370     my_ports[uses_port_name]->uses_port_refs = *new_uses_port;
371
372     // The user code is informed
373     uses_port_changed(uses_port_name,
374                       new_uses_port,
375                       message);
376   }
377   else
378     throw Engines::DSC::PortNotConnected();
379 }
380
381 Ports::PortProperties_ptr
382 Engines_DSC_interface::get_port_properties(const char* port_name) 
383   throw (Engines::DSC::PortNotDefined) 
384 {
385   Ports::PortProperties_ptr rtn_properties = Ports::PortProperties::_nil();
386
387   // Method arg test
388   assert(port_name);
389
390   my_ports_it = my_ports.find(port_name);
391   if (my_ports_it ==  my_ports.end())
392     throw Engines::DSC::PortNotDefined();
393
394   rtn_properties = Ports::PortProperties::_duplicate(my_ports[port_name]->port_prop);
395   return rtn_properties;
396 }
397
398 //Trace functions for DSC operations: a local function (initTrace) and a class method (Engines_DSC_interface::writeEvent)
399 static  int traceType=-1; // 0=stderr;1=file;
400 static  int traceLevel=-1; // 0=no trace;1=normal trace;2=detailed trace
401 static  std::ofstream traceFile;
402 static  std::ostream *out;
403
404 //! Initialize the trace file
405 /*!
406  * The trace file depends on an environment variable (DSC_TRACE). If this variable
407  * is equal to 1, the trace file is a file with the name : <TMPDIR>/<container name>.tce.
408  * In all other cases, the trace file is stderr
409  * The environment variable DSC_TRACELEVEL can be used to suppress the trace (value 0)
410  *
411  * \param containerName the name of the container where the trace is built
412  */
413 static void initTrace(const std::string& containerName)
414 {
415   // if initialization has already been done do nothing
416   if(traceLevel >= 0)return;
417
418   std::string typeenv="0";
419   std::string levelenv="1";
420   char* valenv=0;
421   valenv=getenv("DSC_TRACE");
422   if(valenv)typeenv=valenv;
423   valenv=getenv("DSC_TRACELEVEL");
424   if(valenv)levelenv=valenv;
425
426   if(levelenv=="0")
427     traceLevel=0; // no trace
428   else if(levelenv=="2")
429     traceLevel=2; //detailed trace
430   else
431     traceLevel=1; // normal trace (default)
432
433   if(traceLevel==0)
434     return;
435
436   if(typeenv=="1")
437     {
438       //trace in file
439       traceType=1;
440 #ifdef WIN32
441       std::string logFilename=getenv("TEMP");
442       logFilename += "\\";
443 #else
444       std::string logFilename="/tmp";
445       char* val = getenv("SALOME_TMP_DIR");
446       if(val)
447         {
448           struct stat file_info;
449           stat(val, &file_info);
450           bool is_dir = S_ISDIR(file_info.st_mode);
451           if (is_dir)logFilename=val;
452         }
453       logFilename += "/";
454 #endif
455
456       logFilename=logFilename+containerName+".tce";
457       traceFile.open(logFilename.c_str(), std::ios::out | std::ios::app);
458       out=&traceFile;
459     }
460   else
461     {
462       //trace to stderr (default)
463       traceType=0;
464       out=&std::cerr;
465     }
466   //trace heading
467   out->width(17);
468   *out << "Elapsed time" ;
469   *out << " | " ;
470   out->width(16);
471   *out << "Request" ;
472   *out << " | " ;
473   out->width(16);
474   *out << "Container" ;
475   *out << " | " ;
476   out->width(16);
477   *out << "Instance" ;
478   *out << " | " ;
479   out->width(16);
480   *out << "Port" ;
481   *out << " | " ;
482   out->width(24);
483   *out << "Error";
484   *out << " | " ;
485   *out << "Infos" ;
486   *out << std::endl;
487 }
488
489
490 //! Write a record in the trace file
491 /*!
492  * \param request the name of the request executed
493  * \param containerName the name of the container where the request is executed
494  * \param instance_name the name of the component where the request is executed
495  * \param port_name the name of the port that is concerned
496  * \param error if an error has occured, a string that identifies the error
497  * \param message informations about error or about the request
498  */
499 void Engines_DSC_interface::writeEvent(const char* request,const std::string& containerName, const char* instance_name, 
500                                        const char* port_name, const char* error, const char* message)
501 {
502   if(traceLevel < 0)
503     initTrace(containerName);
504   if(traceLevel == 0)return;
505
506 #ifdef WIN32
507 #else
508   struct timeval tv;
509   gettimeofday(&tv,0);
510   long tt0=tv.tv_sec/3600; //hours
511
512   if(traceType == 2)
513     {
514       //notifier (not used: salome notifier is now obsolete)
515       std::ostringstream msg;
516       msg.width(7);
517       msg << tt0 ;
518       msg << ":" ;
519       long tt1=(tv.tv_sec-3600*tt0)/60;//minutes
520       msg.width(2);
521       msg << tt1 ;
522       msg << ":" ;
523       long tt2=tv.tv_sec - 3600*tt0-60*tt1; //seconds
524       msg.width(2);
525       msg << tt2 ;
526       msg << ":" ;
527       long tt3=tv.tv_usec/1000; //milliseconds
528       msg.width(3);
529       msg << tt3 ;
530       msg << " | " ;
531       msg.width(24);
532       msg << error;
533       msg << " | " ;
534       msg << message ;
535       //send event to notifier (containerName.c_str(),instance_name, request, msg.str().c_str())
536     }
537   else
538     {
539       //cerr or file
540       out->width(7);
541       *out << tt0 ;
542       *out << ":" ;
543       long tt1=(tv.tv_sec-3600*tt0)/60;//minutes
544       out->width(2);
545       *out << tt1 ;
546       *out << ":" ;
547       long tt2=tv.tv_sec - 3600*tt0-60*tt1; //seconds
548       out->width(2);
549       *out << tt2 ;
550       *out << ":" ;
551       long tt3=tv.tv_usec/1000; //milliseconds
552       out->width(3);
553       *out << tt3 ;
554       *out << " | " ;
555       out->width(16);
556       *out << request ;
557       *out << " | " ;
558       out->width(16);
559       *out << containerName ;
560       *out << " | " ;
561       out->width(16);
562       *out << instance_name ;
563       *out << " | " ;
564       out->width(16);
565       *out << port_name ;
566       *out << " | " ;
567       out->width(24);
568       *out << error;
569       *out << " | " ;
570       *out << message ;
571       *out << std::endl;
572     }
573 #endif
574 }
575