Salome HOME
Merge branch 'master' of https://codev-tuleap.cea.fr/plugins/git/salome/gui
[modules/gui.git] / src / Session / Session_ServerCheck.cxx
1 // Copyright (C) 2007-2016  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 class Session_ServerCheck::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 Session_ServerCheck::Session_ServerCheck( QMutex* mutex, QWaitCondition* wc )
139 : QThread(),
140   myMutex( mutex ),
141   myWC( wc ),
142   myCheckCppContainer( false ),
143   myCheckPyContainer( false ),
144   myCheckSVContainer( false ),
145   myAttempts( __DEFAULT__ATTEMPTS__ ),
146   myDelay   ( __DEFAULT__DELAY__ ),
147   myCurrentStep( 0 )
148 {
149   char* cenv;
150   // try to get nb of attempts from environment variable
151   if ( ( cenv = getenv( "CSF_RepeatServerRequest" ) ) && atoi( cenv ) > 0 )
152     myAttempts = atoi( cenv );
153   // try to get delay between attempts from environment variable
154   if ( ( cenv = getenv( "CSF_DelayServerRequest" ) ) && atoi( cenv ) > 0 )
155     myDelay = atoi( cenv );
156
157   // parse command line check if it is necessary to wait SALOME containers
158   QStringList args = QApplication::arguments();
159   for ( int i = 1; i < args.count(); i++ ) {
160     myCheckCppContainer = myCheckCppContainer || args[i] == "CPP";
161     myCheckPyContainer  = myCheckPyContainer  || args[i] == "PY";
162     myCheckSVContainer  = myCheckSVContainer  || args[i] == "SUPERV";
163   }
164   
165   // start thread
166   start();
167 }
168
169 /*!
170   \brief Destructor
171 */
172 Session_ServerCheck::~Session_ServerCheck()
173 {
174   terminate();
175   while( isRunning() );
176 }
177
178 /*!
179   \brief Get current information message.
180   \return current message
181 */
182 QString Session_ServerCheck::currentMessage()
183 {
184   static QStringList messages;
185   if ( messages.isEmpty() ) {
186     messages << tr( "Waiting for naming service..." ); 
187     messages << tr( "Waiting for registry server..." );
188     messages << tr( "Waiting for study server..." );
189     messages << tr( "Waiting for module catalogue server..." );
190     messages << tr( "Waiting for session server..." );
191     messages << tr( "Waiting for C++ container..." );
192     messages << tr( "Waiting for Python container..." );
193     messages << tr( "Waiting for Supervision container..." );
194   }
195   QMutexLocker locker( &myDataMutex );
196   QString msg;
197   int idx = myCurrentStep / myAttempts;
198   if ( idx >= 0 && idx < messages.count() )
199     msg = messages[ idx ];
200   return msg;
201 }
202
203 /*!
204   \brief Get error message.
205   \return error message or null string of there was no any error
206 */
207 QString Session_ServerCheck::error()
208 {
209   QMutexLocker locker( &myDataMutex );
210   return myError;
211 }
212
213 /*!
214   \brief Get current step.
215   \return current step
216 */
217 int Session_ServerCheck::currentStep()
218 {
219   QMutexLocker locker( &myDataMutex );
220   return myCurrentStep;
221 }
222
223 /*!
224   \brief Get total number of check steps.
225   \return total number of steps
226 */
227 int Session_ServerCheck::totalSteps()
228 {
229   QMutexLocker locker( &myDataMutex );
230   int cnt = 5;                       // base servers
231   if ( myCheckCppContainer ) cnt++;  // + C++ container
232   if ( myCheckPyContainer )  cnt++;  // + Python container
233   if ( myCheckSVContainer )  cnt++;  // + supervision container
234   return cnt * myAttempts;
235 }
236
237 /*!
238   \brief Modify current step.
239   \param step new current step value
240 */
241 void Session_ServerCheck::setStep( const int step )
242 {
243   QMutexLocker locker( &myDataMutex );
244   myCurrentStep = step;
245 }
246
247 /*!
248   \brief Set error message.
249   \param msg error message
250 */
251 void Session_ServerCheck::setError( const QString& msg )
252 {
253   QMutexLocker locker( &myDataMutex );
254   myError = msg;
255 }
256
257 /*!
258   \brief Thread loop function. Performs SALOME servers check.
259 */
260 void Session_ServerCheck::run()
261 {
262   // start check servers
263   int current = 0;
264   QString error;
265   Qtx::CmdLineArgs args;
266   
267   // 1. Check naming service
268   for ( int i = 0; i < myAttempts; i++ ) {
269     Locker locker( this );
270
271     setStep( current * myAttempts + i );
272
273     try {
274       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
275       CORBA::ORB_var orb = init( args.argc(), args.argv() );
276       CORBA::Object_var obj = orb->resolve_initial_references( "NameService" );
277       CosNaming::NamingContext_var _root_context = CosNaming::NamingContext::_narrow( obj );
278       if ( !CORBA::is_nil( _root_context ) ) {
279         setStep( ++current * myAttempts );
280         break;
281       }
282     }
283     catch( CORBA::COMM_FAILURE& ) {
284       MESSAGE( "CORBA::COMM_FAILURE: unable to contact the naming service" );
285     }
286     catch( ... ) {
287       MESSAGE( "Unknown Exception: unable to contact the naming service" );
288     }
289
290     if ( i == myAttempts-1 ) {
291       setError( tr( "Unable to contact the naming service.\n" ) );
292       return;
293     }
294   }
295
296   // 2. Check registry server
297   for ( int i = 0; i < myAttempts ; i++ ) {
298     Locker locker( this );
299
300     setStep( current * myAttempts + i );
301
302     try {
303       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
304       CORBA::ORB_var orb = init( args.argc(), args.argv() );
305       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
306       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
307       NS.init_orb( orb );
308       CORBA::Object_var obj = NS.Resolve( "/Registry" );
309       Registry::Components_var registry = Registry::Components::_narrow( obj );
310       if ( !CORBA::is_nil( registry ) ) {
311         MESSAGE( "/Registry is found" );
312         registry->ping();
313         MESSAGE( "Registry was activated" );
314         setStep( ++current * myAttempts );
315         break;
316       }
317     }
318     catch ( ServiceUnreachable& ) {
319       MESSAGE( "Caught exception: Naming Service unreachable." );
320       error = "Naming service unreachable";
321     }
322     catch ( CORBA::COMM_FAILURE& ) {
323       MESSAGE( "Caught CORBA::SystemException CommFailure." );
324       error = "Caught CORBA::SystemException CommFailure.";
325     }
326     catch ( CORBA::SystemException& ) {
327       MESSAGE( "Caught CORBA::SystemException." );
328       error = "Caught CORBA::SystemException.";
329     }
330     catch ( CORBA::Exception& ) {
331       MESSAGE( "Caught CORBA::Exception." );
332       error = "Caught CORBA::Exception.";
333     }
334     catch (...) {
335       MESSAGE( "Caught unknown exception." );
336       error = "Caught unknown exception.";
337     }
338
339     if ( i == myAttempts-1 ) {
340       setError( tr( "Registry server is not found.\n%1" ).arg ( error ) );
341       return;
342     }
343   }
344
345   // 3. Check data server
346   for ( int i = 0; i < myAttempts ; i++ ) {
347     Locker locker( this );
348
349     setStep( current * myAttempts + i );
350
351     try {
352       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
353       CORBA::ORB_var orb = init( args.argc(), args.argv() );
354       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
355       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
356       NS.init_orb( orb );
357       CORBA::Object_var obj = NS.Resolve( "/Study" );
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.\n%1" ).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       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
402       CORBA::ORB_var orb = init( args.argc(), args.argv() );
403       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
404       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
405       NS.init_orb( orb );
406       CORBA::Object_var obj = NS.Resolve( "/Kernel/ModulCatalog" );
407       SALOME_ModuleCatalog::ModuleCatalog_var catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow( obj );
408       if ( !CORBA::is_nil( catalog ) ){
409         MESSAGE( "/Kernel/ModulCatalog is found" );
410         catalog->ping();
411         MESSAGE( "ModuleCatalog was activated" );
412         setStep( ++current * myAttempts );
413         break;
414       }
415     }
416     catch ( ServiceUnreachable& ) {
417       MESSAGE( "Caught exception: Naming Service unreachable." );
418       error = "Naming service unreachable";
419     }
420     catch ( CORBA::COMM_FAILURE& ) {
421       MESSAGE( "Caught CORBA::SystemException CommFailure." );
422       error = "Caught CORBA::SystemException CommFailure.";
423     }
424     catch ( CORBA::SystemException& ) {
425       MESSAGE( "Caught CORBA::SystemException." );
426       error = "Caught CORBA::SystemException.";
427     }
428     catch ( CORBA::Exception& ) {
429       MESSAGE( "Caught CORBA::Exception." );
430       error = "Caught CORBA::Exception.";
431     }
432     catch (...) {
433       MESSAGE( "Caught unknown exception." );
434       error = "Caught unknown exception.";
435     }
436
437     if ( i == myAttempts-1 ) {
438       setError( tr( "Module catalogue server is not found.\n%1" ).arg ( error ) );
439       return;
440     }
441   }
442
443   // 5. Check data server
444   for ( int i = 0; i < myAttempts ; i++ ) {
445     Locker locker( this );
446
447     setStep( current * myAttempts + i );
448
449     try {
450       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
451       CORBA::ORB_var orb = init( args.argc(), args.argv() );
452       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
453       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
454       NS.init_orb( orb );
455       CORBA::Object_var obj = NS.Resolve( "/Kernel/Session" );
456       SALOME::Session_var session = SALOME::Session::_narrow( obj );
457       if ( !CORBA::is_nil( session ) ) {
458         MESSAGE( "/Kernel/Session is found" );
459         session->ping();
460         MESSAGE( "SALOME_Session was activated" );
461         setStep( ++current * myAttempts );
462         break;
463       }
464     }
465     catch ( ServiceUnreachable& ) {
466       MESSAGE( "Caught exception: Naming Service unreachable." );
467       error = "Naming service unreachable";
468     }
469     catch ( CORBA::COMM_FAILURE& ) {
470       MESSAGE( "Caught CORBA::SystemException CommFailure." );
471       error = "Caught CORBA::SystemException CommFailure.";
472     }
473     catch ( CORBA::SystemException& ) {
474       MESSAGE( "Caught CORBA::SystemException." );
475       error = "Caught CORBA::SystemException.";
476     }
477     catch ( CORBA::Exception& ) {
478       MESSAGE( "Caught CORBA::Exception." );
479       error = "Caught CORBA::Exception.";
480     }
481     catch (...) {
482       MESSAGE( "Caught unknown exception." );
483       error = "Caught unknown exception.";
484     }
485
486     if ( i == myAttempts-1 ) {
487       setError( tr( "Session server is not found.\n%1" ).arg ( error ) );
488       return;
489     }
490   }
491
492   // 6. Check C++ container
493   if ( myCheckCppContainer ) {
494     for ( int i = 0; i < myAttempts ; i++ ) {
495       Locker locker( this );
496       
497       setStep( current * myAttempts + i );
498
499       try {
500         ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
501         CORBA::ORB_var orb = init( args.argc(), args.argv() );
502         SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
503         ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
504         NS.init_orb( orb );
505         QString containerName = QString( "/Containers/%1/FactoryServer" ).arg( Kernel_Utils::GetHostname().c_str() );
506         CORBA::Object_var obj = NS.Resolve( containerName.toLatin1() );
507         Engines::Container_var FScontainer = Engines::Container::_narrow( obj );
508         if ( !CORBA::is_nil( FScontainer ) ) {
509           MESSAGE( containerName.toLatin1().constData() << " is found" );
510           FScontainer->ping();
511           MESSAGE( "FactoryServer container was activated" );
512           setStep( ++current * myAttempts );
513           break;
514         }
515       }
516       catch ( ServiceUnreachable& ) {
517         MESSAGE( "Caught exception: Naming Service unreachable." );
518         error = "Naming service unreachable";
519       }
520       catch ( CORBA::COMM_FAILURE& ) {
521         MESSAGE( "Caught CORBA::SystemException CommFailure." );
522         error = "Caught CORBA::SystemException CommFailure.";
523       }
524       catch ( CORBA::SystemException& ) {
525         MESSAGE( "Caught CORBA::SystemException." );
526         error = "Caught CORBA::SystemException.";
527       }
528       catch ( CORBA::Exception& ) {
529         MESSAGE( "Caught CORBA::Exception." );
530         error = "Caught CORBA::Exception.";
531       }
532       catch (...) {
533         MESSAGE( "Caught unknown exception." );
534         error = "Caught unknown exception.";
535       }
536       
537       if ( i == myAttempts-1 ) {
538         setError( tr( "C++ container is not found.\n%1" ).arg ( error ) );
539         return;
540       }
541     }
542   }
543
544   // 7. Check Python container
545   if ( myCheckPyContainer ) {
546     for ( int i = 0; i < myAttempts ; i++ ) {
547       Locker locker( this );
548       
549       setStep( current * myAttempts + i );
550
551       try {
552         ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
553         CORBA::ORB_var orb = init( args.argc(), args.argv() );
554         SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
555         ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
556         NS.init_orb( orb );
557         QString containerName = QString( "/Containers/%1/FactoryServerPy" ).arg( Kernel_Utils::GetHostname().c_str() );
558         CORBA::Object_var obj = NS.Resolve( containerName.toLatin1() );
559         Engines::Container_var FSPcontainer = Engines::Container::_narrow( obj );
560         if ( !CORBA::is_nil( FSPcontainer ) ) {
561           MESSAGE( containerName.toLatin1().constData() << " is found" );
562           FSPcontainer->ping();
563           MESSAGE("FactoryServerPy container was activated");
564           setStep( ++current * myAttempts );
565           break;
566         }
567       }
568       catch ( ServiceUnreachable& ) {
569         MESSAGE( "Caught exception: Naming Service unreachable." );
570         error = "Naming service unreachable";
571       }
572       catch ( CORBA::COMM_FAILURE& ) {
573         MESSAGE( "Caught CORBA::SystemException CommFailure." );
574         error = "Caught CORBA::SystemException CommFailure.";
575       }
576       catch ( CORBA::SystemException& ) {
577         MESSAGE( "Caught CORBA::SystemException." );
578         error = "Caught CORBA::SystemException.";
579       }
580       catch ( CORBA::Exception& ) {
581         MESSAGE( "Caught CORBA::Exception." );
582         error = "Caught CORBA::Exception.";
583       }
584       catch (...) {
585         MESSAGE( "Caught unknown exception." );
586         error = "Caught unknown exception.";
587       }
588
589       if ( i == myAttempts-1 ) {
590         setError( tr( "Python container is not found.\n%1" ).arg ( error ) );
591         return;
592       }
593     }
594   }
595
596   // 8. Check supervision container
597   if ( myCheckSVContainer ) {
598     for ( int i = 0; i < myAttempts ; i++ ) {
599       Locker locker( this );
600       
601       setStep( current * myAttempts + i );
602
603       try {
604         ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
605         CORBA::ORB_var orb = init( args.argc(), args.argv() );
606         SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
607         ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
608         NS.init_orb( orb );
609         QString containerName = QString( "/Containers/%1/SuperVisionContainer" ).arg( Kernel_Utils::GetHostname().c_str() );
610         CORBA::Object_var obj = NS.Resolve( containerName.toLatin1() );
611         Engines::Container_var SVcontainer = Engines::Container::_narrow( obj );
612         if ( !CORBA::is_nil( SVcontainer ) ) {
613           MESSAGE( containerName.toLatin1().constData() << " is found" );
614           SVcontainer->ping();
615           MESSAGE("SuperVisionContainer container was activated");
616           setStep( ++current * myAttempts );
617           break;
618         }
619       }
620       catch ( ServiceUnreachable& ) {
621         MESSAGE( "Caught exception: Naming Service unreachable." );
622         error = "Naming service unreachable";
623       }
624       catch ( CORBA::COMM_FAILURE& ) {
625         MESSAGE( "Caught CORBA::SystemException CommFailure." );
626         error = "Caught CORBA::SystemException CommFailure.";
627       }
628       catch ( CORBA::SystemException& ) {
629         MESSAGE( "Caught CORBA::SystemException." );
630         error = "Caught CORBA::SystemException.";
631       }
632       catch ( CORBA::Exception& ) {
633         MESSAGE( "Caught CORBA::Exception." );
634         error = "Caught CORBA::Exception.";
635       }
636       catch (...) {
637         MESSAGE( "Caught unknown exception." );
638         error = "Caught unknown exception.";
639       }
640     
641       if ( i == myAttempts-1 ) {
642         setError( tr( "Supervision container is not found.\n%1" ).arg ( error ) );
643         return;
644       }
645     }
646   }
647 }