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