Salome HOME
updated copyright message
[modules/gui.git] / src / Session / Session_ServerCheck.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, 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   : Session_ServerCheck.cxx
24 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
25 //
26 #include "Session_ServerCheck.hxx"
27
28 #include <SALOMEconfig.h>
29 #include CORBA_CLIENT_HEADER(SALOME_Session)
30 #include CORBA_CLIENT_HEADER(SALOME_Registry)
31 #include CORBA_CLIENT_HEADER(SALOMEDS)
32 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
33 #include CORBA_CLIENT_HEADER(SALOME_Component)
34
35 #include "Utils_SINGLETON.hxx"
36 #include "SALOME_NamingService.hxx"
37 #include "Basics_Utils.hxx"
38 #include "utilities.h"
39 #include "Qtx.h"
40
41 #include <QApplication> 
42 #include <QWaitCondition>
43 #include <QMutexLocker>
44 #include <QStringList>
45
46 //
47 // Default settings
48 //
49
50 /*!
51   \brief Default number of attemtps to check SALOME server.
52
53   This value can be changed by setting the CSF_RepeatServerRequest
54   environment variable. For example, to set number of check attempts
55   for each server to 1000:
56   \code
57   setenv CSF_RepeatServerRequest 1000
58   \endcode
59 */
60 const int __DEFAULT__ATTEMPTS__ = 300;
61
62 /*!
63   \brief Default delay between attempts (in microseconds).
64
65   This value can be changed by setting the CSF_DelayServerRequest
66   environment variable. For example, to set delay between attemtps
67   to check SALOME servers to 100000 (0.1 second):
68   \code
69   setenv CSF_DelayServerRequest 100000
70   \endcode
71 */
72 const int __DEFAULT__DELAY__ = 50000;
73
74 // The exception being thrown out of a destructor,
75 // that is not allowed by default in C++11.
76
77 #if __cplusplus >= 201103L
78 # define TYPE_NOEXCEPT noexcept(false)
79 #else
80 # define TYPE_NOEXCEPT
81 #endif
82
83 /*!
84   \classSession_ServerCheck::Locker
85   \brief Automatic locker/unlocker.
86   \internal
87 */
88
89 template<class MY_CLS>
90 class Session_ServerCheck<MY_CLS>::Locker
91 {
92 public:
93   /*!
94     \brief Constructor. Tries to aquire lock.
95   */
96   Locker( Session_ServerCheck* sc ) 
97     : myChecker( sc )
98   {
99     myChecker->myMutex->lock();
100     myChecker->myMutex->unlock();
101   }
102   /*!
103     \brief Destructor. Wakes the calling thread and goes sleeping.
104   */
105   ~Locker() TYPE_NOEXCEPT
106   {
107     myChecker->myWC->wakeAll();
108     myChecker->usleep( myChecker->myDelay );
109   }
110 private:
111   Session_ServerCheck* myChecker;
112 };
113
114 /*!
115   \class Session_ServerCheck
116   \brief The class Session_ServerCheck is used to check SALOME
117   servers availability.
118   
119   It runs in the secondrary thread. The number of attemts to check
120   each SALOME server and the time delay between checks can be specified
121   via setting the CSF_RepeatServerRequest and CSF_DelayServerRequest
122   environment variables.
123
124   Total number of the check attempts can be retrieved via totalSteps()
125   method and current check step can be retrieved via currentStep() method.
126
127   The method currentMessage() can be used to get the information message
128   about what SALOME server is currently checked. If any error occured (some
129   server could not be found) the thread loop is stopped and error status
130   is set. Error message can be retrieved with the error() method.
131 */
132
133 /*!
134   \brief Constructor.
135   \param mutex a mutex used to serialize progress operations (splash)
136   \param wc a wait condition used in combination with \a mutex
137 */
138 template<class MY_NS>
139 Session_ServerCheck<MY_NS>::Session_ServerCheck( QMutex* mutex, QWaitCondition* wc )
140 : QThread(),
141   myMutex( mutex ),
142   myWC( wc ),
143   myCheckCppContainer( false ),
144   myCheckPyContainer( false ),
145   myCheckSVContainer( false ),
146   myAttempts( __DEFAULT__ATTEMPTS__ ),
147   myDelay   ( __DEFAULT__DELAY__ ),
148   myCurrentStep( 0 )
149 {
150   char* cenv;
151   // try to get nb of attempts from environment variable
152   if ( ( cenv = getenv( "CSF_RepeatServerRequest" ) ) && atoi( cenv ) > 0 )
153     myAttempts = atoi( cenv );
154   // try to get delay between attempts from environment variable
155   if ( ( cenv = getenv( "CSF_DelayServerRequest" ) ) && atoi( cenv ) > 0 )
156     myDelay = atoi( cenv );
157
158   // parse command line check if it is necessary to wait SALOME containers
159   QStringList args = QApplication::arguments();
160   for ( int i = 1; i < args.count(); i++ ) {
161     myCheckCppContainer = myCheckCppContainer || args[i] == "CPP";
162     myCheckPyContainer  = myCheckPyContainer  || args[i] == "PY";
163     myCheckSVContainer  = myCheckSVContainer  || args[i] == "SUPERV";
164   }
165   
166   // start thread
167   start();
168 }
169
170 /*!
171   \brief Destructor
172 */
173 template<class MY_NS>
174 Session_ServerCheck<MY_NS>::~Session_ServerCheck()
175 {
176   terminate();
177   while( isRunning() );
178 }
179
180 /*!
181   \brief Get current information message.
182   \return current message
183 */
184 template<class MY_NS>
185 QString Session_ServerCheck<MY_NS>::currentMessage()
186 {
187   static QStringList messages;
188   if ( messages.isEmpty() ) {
189     messages << tr( "Waiting for naming service..." ); 
190     messages << tr( "Waiting for registry server..." );
191     messages << tr( "Waiting for study server..." );
192     messages << tr( "Waiting for module catalogue server..." );
193     messages << tr( "Waiting for session server..." );
194     messages << tr( "Waiting for C++ container..." );
195     messages << tr( "Waiting for Python container..." );
196     messages << tr( "Waiting for Supervision container..." );
197   }
198   QMutexLocker locker( &myDataMutex );
199   QString msg;
200   int idx = myCurrentStep / myAttempts;
201   if ( idx >= 0 && idx < messages.count() )
202     msg = messages[ idx ];
203   return msg;
204 }
205
206 /*!
207   \brief Get error message.
208   \return error message or null string of there was no any error
209 */
210 template<class MY_NS>
211 QString Session_ServerCheck<MY_NS>::error()
212 {
213   QMutexLocker locker( &myDataMutex );
214   return myError;
215 }
216
217 /*!
218   \brief Get current step.
219   \return current step
220 */
221 template<class MY_NS>
222 int Session_ServerCheck<MY_NS>::currentStep()
223 {
224   QMutexLocker locker( &myDataMutex );
225   return myCurrentStep;
226 }
227
228 /*!
229   \brief Get total number of check steps.
230   \return total number of steps
231 */
232 template<class MY_NS>
233 int Session_ServerCheck<MY_NS>::totalSteps()
234 {
235   QMutexLocker locker( &myDataMutex );
236   int cnt = 5;                       // base servers
237   if ( myCheckCppContainer ) cnt++;  // + C++ container
238   if ( myCheckPyContainer )  cnt++;  // + Python container
239   if ( myCheckSVContainer )  cnt++;  // + supervision container
240   return cnt * myAttempts;
241 }
242
243 /*!
244   \brief Modify current step.
245   \param step new current step value
246 */
247 template<class MY_NS>
248 void Session_ServerCheck<MY_NS>::setStep( const int step )
249 {
250   QMutexLocker locker( &myDataMutex );
251   myCurrentStep = step;
252 }
253
254 /*!
255   \brief Set error message.
256   \param msg error message
257 */
258 template<class MY_NS>
259 void Session_ServerCheck<MY_NS>::setError( const QString& msg )
260 {
261   QMutexLocker locker( &myDataMutex );
262   myError = msg;
263 }
264
265 /*!
266   \brief Thread loop function. Performs SALOME servers check.
267 */
268 template<class MY_NS>
269 void Session_ServerCheck<MY_NS>::run()
270 {
271   // start check servers
272   int current = 0;
273   QString error;
274   Qtx::CmdLineArgs args;
275   
276   // 1. Check naming service
277   for ( int i = 0; i < myAttempts; i++ ) {
278     Locker locker( this );
279
280     setStep( current * myAttempts + i );
281
282     try {
283       bool forceOK = false;
284       CosNaming::NamingContext_var _root_context = MY_NS::checkTrueNamingServiceIfExpected(args.argc(), args.argv(),forceOK);
285       if ( forceOK ||  !CORBA::is_nil( _root_context ) ) {
286         setStep( ++current * myAttempts );
287         break;
288       }
289     }
290     catch( CORBA::COMM_FAILURE& ) {
291       MESSAGE( "CORBA::COMM_FAILURE: unable to contact the naming service" );
292     }
293     catch( ... ) {
294       MESSAGE( "Unknown Exception: unable to contact the naming service" );
295     }
296
297     if ( i == myAttempts-1 ) {
298       setError( tr( "Unable to contact the naming service." ) + "\n" );
299       return;
300     }
301   }
302
303   QString errfmt = "\n%1";
304
305   // 2. Check registry server
306   for ( int i = 0; i < myAttempts ; i++ ) {
307     Locker locker( this );
308
309     setStep( current * myAttempts + i );
310
311     try {
312       CORBA::Object_var obj = MY_NS::forServerChecker("/Registry", args.argc(), args.argv());
313       Registry::Components_var registry = Registry::Components::_narrow( obj );
314       if ( !CORBA::is_nil( registry ) ) {
315         MESSAGE( "/Registry is found" );
316         registry->ping();
317         MESSAGE( "Registry was activated" );
318         setStep( ++current * myAttempts );
319         break;
320       }
321     }
322     catch ( ServiceUnreachable& ) {
323       MESSAGE( "Caught exception: Naming Service unreachable." );
324       error = "Naming service unreachable";
325     }
326     catch ( CORBA::COMM_FAILURE& ) {
327       MESSAGE( "Caught CORBA::SystemException CommFailure." );
328       error = "Caught CORBA::SystemException CommFailure.";
329     }
330     catch ( CORBA::SystemException& ) {
331       MESSAGE( "Caught CORBA::SystemException." );
332       error = "Caught CORBA::SystemException.";
333     }
334     catch ( CORBA::Exception& ) {
335       MESSAGE( "Caught CORBA::Exception." );
336       error = "Caught CORBA::Exception.";
337     }
338     catch (...) {
339       MESSAGE( "Caught unknown exception." );
340       error = "Caught unknown exception.";
341     }
342
343     if ( i == myAttempts-1 ) {
344       setError( tr( "Registry server is not found." ) + errfmt.arg( error ) );
345       return;
346     }
347   }
348
349   // 3. Check data server
350   for ( int i = 0; i < myAttempts ; i++ ) {
351     Locker locker( this );
352
353     setStep( current * myAttempts + i );
354
355     try {
356       CORBA::Object_var obj = MY_NS::forServerChecker("/Study", args.argc(), args.argv());
357       SALOMEDS::Study_var study = SALOMEDS::Study::_narrow( obj );
358       if ( !CORBA::is_nil( study ) ) {
359         MESSAGE( "/Study is found" );
360         study->ping();
361         MESSAGE( "Study was activated" );
362         setStep( ++current * myAttempts );
363         break;
364       }
365     }
366     catch ( ServiceUnreachable& ) {
367       MESSAGE( "Caught exception: Naming Service unreachable." );
368       error = "Naming service unreachable";
369     }
370     catch ( CORBA::COMM_FAILURE& ) {
371       MESSAGE( "Caught CORBA::SystemException CommFailure." );
372       error = "Caught CORBA::SystemException CommFailure.";
373     }
374     catch ( CORBA::SystemException& ) {
375       MESSAGE( "Caught CORBA::SystemException." );
376       error = "Caught CORBA::SystemException.";
377     }
378     catch ( CORBA::Exception& ) {
379       MESSAGE( "Caught CORBA::Exception." );
380       error = "Caught CORBA::Exception.";
381     }
382     catch (...) {
383       MESSAGE( "Caught unknown exception." );
384       error = "Caught unknown exception.";
385     }
386
387     if ( i == myAttempts-1 ) {
388       setError( tr( "Study server is not found." ) + errfmt.arg( error ) );
389       return;
390     }
391   }
392   
393   // 4. Check module catalogue server
394   for ( int i = 0; i < myAttempts ; i++ ) {
395     Locker locker( this );
396
397     setStep( current * myAttempts + i );
398
399     try {
400       CORBA::Object_var obj = MY_NS::forServerChecker("/Kernel/ModulCatalog", args.argc(), args.argv());
401       SALOME_ModuleCatalog::ModuleCatalog_var catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow( obj );
402       if ( !CORBA::is_nil( catalog ) ){
403         MESSAGE( "/Kernel/ModulCatalog is found" );
404         catalog->ping();
405         MESSAGE( "ModuleCatalog was activated" );
406         setStep( ++current * myAttempts );
407         break;
408       }
409     }
410     catch ( ServiceUnreachable& ) {
411       MESSAGE( "Caught exception: Naming Service unreachable." );
412       error = "Naming service unreachable";
413     }
414     catch ( CORBA::COMM_FAILURE& ) {
415       MESSAGE( "Caught CORBA::SystemException CommFailure." );
416       error = "Caught CORBA::SystemException CommFailure.";
417     }
418     catch ( CORBA::SystemException& ) {
419       MESSAGE( "Caught CORBA::SystemException." );
420       error = "Caught CORBA::SystemException.";
421     }
422     catch ( CORBA::Exception& ) {
423       MESSAGE( "Caught CORBA::Exception." );
424       error = "Caught CORBA::Exception.";
425     }
426     catch (...) {
427       MESSAGE( "Caught unknown exception." );
428       error = "Caught unknown exception.";
429     }
430
431     if ( i == myAttempts-1 ) {
432       setError( tr( "Module catalogue server is not found." ) + errfmt.arg( error ) );
433       return;
434     }
435   }
436
437   // 5. Check data server
438   for ( int i = 0; i < myAttempts ; i++ ) {
439     Locker locker( this );
440
441     setStep( current * myAttempts + i );
442
443     try {
444       CORBA::Object_var obj = MY_NS::forServerChecker("/Kernel/Session", args.argc(), args.argv());
445       SALOME::Session_var session = SALOME::Session::_narrow( obj );
446       if ( !CORBA::is_nil( session ) ) {
447         MESSAGE( "/Kernel/Session is found" );
448         session->ping();
449         MESSAGE( "SALOME_Session was activated" );
450         setStep( ++current * myAttempts );
451         break;
452       }
453     }
454     catch ( ServiceUnreachable& ) {
455       MESSAGE( "Caught exception: Naming Service unreachable." );
456       error = "Naming service unreachable";
457     }
458     catch ( CORBA::COMM_FAILURE& ) {
459       MESSAGE( "Caught CORBA::SystemException CommFailure." );
460       error = "Caught CORBA::SystemException CommFailure.";
461     }
462     catch ( CORBA::SystemException& ) {
463       MESSAGE( "Caught CORBA::SystemException." );
464       error = "Caught CORBA::SystemException.";
465     }
466     catch ( CORBA::Exception& ) {
467       MESSAGE( "Caught CORBA::Exception." );
468       error = "Caught CORBA::Exception.";
469     }
470     catch (...) {
471       MESSAGE( "Caught unknown exception." );
472       error = "Caught unknown exception.";
473     }
474
475     if ( i == myAttempts-1 ) {
476       setError( tr( "Session server is not found." ) + errfmt.arg( error ) );
477       return;
478     }
479   }
480
481   // 6. Check C++ container
482   if ( myCheckCppContainer ) {
483     for ( int i = 0; i < myAttempts ; i++ ) {
484       Locker locker( this );
485       
486       setStep( current * myAttempts + i );
487
488       try {
489         QString containerName = QString( "/Containers/%1/FactoryServer" ).arg( Kernel_Utils::GetHostname().c_str() );
490         CORBA::Object_var obj = MY_NS::forServerChecker(containerName.toLatin1(), args.argc(), args.argv());
491         Engines::Container_var FScontainer = Engines::Container::_narrow( obj );
492         if ( !CORBA::is_nil( FScontainer ) ) {
493           MESSAGE( containerName.toLatin1().constData() << " is found" );
494           FScontainer->ping();
495           MESSAGE( "FactoryServer container was activated" );
496           setStep( ++current * myAttempts );
497           break;
498         }
499       }
500       catch ( ServiceUnreachable& ) {
501         MESSAGE( "Caught exception: Naming Service unreachable." );
502         error = "Naming service unreachable";
503       }
504       catch ( CORBA::COMM_FAILURE& ) {
505         MESSAGE( "Caught CORBA::SystemException CommFailure." );
506         error = "Caught CORBA::SystemException CommFailure.";
507       }
508       catch ( CORBA::SystemException& ) {
509         MESSAGE( "Caught CORBA::SystemException." );
510         error = "Caught CORBA::SystemException.";
511       }
512       catch ( CORBA::Exception& ) {
513         MESSAGE( "Caught CORBA::Exception." );
514         error = "Caught CORBA::Exception.";
515       }
516       catch (...) {
517         MESSAGE( "Caught unknown exception." );
518         error = "Caught unknown exception.";
519       }
520       
521       if ( i == myAttempts-1 ) {
522         setError( tr( "C++ container is not found." ) + errfmt.arg( error ) );
523         return;
524       }
525     }
526   }
527
528   // 7. Check Python container
529   if ( myCheckPyContainer ) {
530     for ( int i = 0; i < myAttempts ; i++ ) {
531       Locker locker( this );
532       
533       setStep( current * myAttempts + i );
534
535       try {
536         QString containerName = QString( "/Containers/%1/FactoryServerPy" ).arg( Kernel_Utils::GetHostname().c_str() );
537         CORBA::Object_var obj = MY_NS::forServerChecker(containerName.toLatin1(), args.argc(), args.argv());
538         Engines::Container_var FSPcontainer = Engines::Container::_narrow( obj );
539         if ( !CORBA::is_nil( FSPcontainer ) ) {
540           MESSAGE( containerName.toLatin1().constData() << " is found" );
541           FSPcontainer->ping();
542           MESSAGE("FactoryServerPy container was activated");
543           setStep( ++current * myAttempts );
544           break;
545         }
546       }
547       catch ( ServiceUnreachable& ) {
548         MESSAGE( "Caught exception: Naming Service unreachable." );
549         error = "Naming service unreachable";
550       }
551       catch ( CORBA::COMM_FAILURE& ) {
552         MESSAGE( "Caught CORBA::SystemException CommFailure." );
553         error = "Caught CORBA::SystemException CommFailure.";
554       }
555       catch ( CORBA::SystemException& ) {
556         MESSAGE( "Caught CORBA::SystemException." );
557         error = "Caught CORBA::SystemException.";
558       }
559       catch ( CORBA::Exception& ) {
560         MESSAGE( "Caught CORBA::Exception." );
561         error = "Caught CORBA::Exception.";
562       }
563       catch (...) {
564         MESSAGE( "Caught unknown exception." );
565         error = "Caught unknown exception.";
566       }
567
568       if ( i == myAttempts-1 ) {
569         setError( tr( "Python container is not found." ) + errfmt.arg( error ) );
570         return;
571       }
572     }
573   }
574
575   // 8. Check supervision container
576   if ( myCheckSVContainer ) {
577     for ( int i = 0; i < myAttempts ; i++ ) {
578       Locker locker( this );
579       
580       setStep( current * myAttempts + i );
581
582       try {
583         QString containerName = QString( "/Containers/%1/SuperVisionContainer" ).arg( Kernel_Utils::GetHostname().c_str() );
584         CORBA::Object_var obj = MY_NS::forServerChecker(containerName.toLatin1(), args.argc(), args.argv());
585         Engines::Container_var SVcontainer = Engines::Container::_narrow( obj );
586         if ( !CORBA::is_nil( SVcontainer ) ) {
587           MESSAGE( containerName.toLatin1().constData() << " is found" );
588           SVcontainer->ping();
589           MESSAGE("SuperVisionContainer container was activated");
590           setStep( ++current * myAttempts );
591           break;
592         }
593       }
594       catch ( ServiceUnreachable& ) {
595         MESSAGE( "Caught exception: Naming Service unreachable." );
596         error = "Naming service unreachable";
597       }
598       catch ( CORBA::COMM_FAILURE& ) {
599         MESSAGE( "Caught CORBA::SystemException CommFailure." );
600         error = "Caught CORBA::SystemException CommFailure.";
601       }
602       catch ( CORBA::SystemException& ) {
603         MESSAGE( "Caught CORBA::SystemException." );
604         error = "Caught CORBA::SystemException.";
605       }
606       catch ( CORBA::Exception& ) {
607         MESSAGE( "Caught CORBA::Exception." );
608         error = "Caught CORBA::Exception.";
609       }
610       catch (...) {
611         MESSAGE( "Caught unknown exception." );
612         error = "Caught unknown exception.";
613       }
614     
615       if ( i == myAttempts-1 ) {
616         setError( tr( "Supervision container is not found." ) + errfmt.arg( error ) );
617         return;
618       }
619     }
620   }
621 }
622
623 #include "Session_NS_wrapper.hxx"
624
625 template class Session_ServerCheck<OldStyleNS>;
626 template class Session_ServerCheck<NewStyleNS>;