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