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