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