Salome HOME
Merge branch 'occ/shaper2smesh'
[modules/gui.git] / src / Session / Session_ServerCheck.cxx
1 // Copyright (C) 2007-2019  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   QString errfmt = "\n%1";
297
298   // 2. Check registry server
299   for ( int i = 0; i < myAttempts ; i++ ) {
300     Locker locker( this );
301
302     setStep( current * myAttempts + i );
303
304     try {
305       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
306       CORBA::ORB_var orb = init( args.argc(), args.argv() );
307       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
308       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
309       NS.init_orb( orb );
310       CORBA::Object_var obj = NS.Resolve( "/Registry" );
311       Registry::Components_var registry = Registry::Components::_narrow( obj );
312       if ( !CORBA::is_nil( registry ) ) {
313         MESSAGE( "/Registry is found" );
314         registry->ping();
315         MESSAGE( "Registry was activated" );
316         setStep( ++current * myAttempts );
317         break;
318       }
319     }
320     catch ( ServiceUnreachable& ) {
321       MESSAGE( "Caught exception: Naming Service unreachable." );
322       error = "Naming service unreachable";
323     }
324     catch ( CORBA::COMM_FAILURE& ) {
325       MESSAGE( "Caught CORBA::SystemException CommFailure." );
326       error = "Caught CORBA::SystemException CommFailure.";
327     }
328     catch ( CORBA::SystemException& ) {
329       MESSAGE( "Caught CORBA::SystemException." );
330       error = "Caught CORBA::SystemException.";
331     }
332     catch ( CORBA::Exception& ) {
333       MESSAGE( "Caught CORBA::Exception." );
334       error = "Caught CORBA::Exception.";
335     }
336     catch (...) {
337       MESSAGE( "Caught unknown exception." );
338       error = "Caught unknown exception.";
339     }
340
341     if ( i == myAttempts-1 ) {
342       setError( tr( "Registry server is not found." ) + errfmt.arg( error ) );
343       return;
344     }
345   }
346
347   // 3. Check data server
348   for ( int i = 0; i < myAttempts ; i++ ) {
349     Locker locker( this );
350
351     setStep( current * myAttempts + i );
352
353     try {
354       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
355       CORBA::ORB_var orb = init( args.argc(), args.argv() );
356       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
357       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
358       NS.init_orb( orb );
359       CORBA::Object_var obj = NS.Resolve( "/Study" );
360       SALOMEDS::Study_var study = SALOMEDS::Study::_narrow( obj );
361       if ( !CORBA::is_nil( study ) ) {
362         MESSAGE( "/Study is found" );
363         study->ping();
364         MESSAGE( "Study was activated" );
365         setStep( ++current * myAttempts );
366         break;
367       }
368     }
369     catch ( ServiceUnreachable& ) {
370       MESSAGE( "Caught exception: Naming Service unreachable." );
371       error = "Naming service unreachable";
372     }
373     catch ( CORBA::COMM_FAILURE& ) {
374       MESSAGE( "Caught CORBA::SystemException CommFailure." );
375       error = "Caught CORBA::SystemException CommFailure.";
376     }
377     catch ( CORBA::SystemException& ) {
378       MESSAGE( "Caught CORBA::SystemException." );
379       error = "Caught CORBA::SystemException.";
380     }
381     catch ( CORBA::Exception& ) {
382       MESSAGE( "Caught CORBA::Exception." );
383       error = "Caught CORBA::Exception.";
384     }
385     catch (...) {
386       MESSAGE( "Caught unknown exception." );
387       error = "Caught unknown exception.";
388     }
389
390     if ( i == myAttempts-1 ) {
391       setError( tr( "Study server is not found." ) + errfmt.arg( error ) );
392       return;
393     }
394   }
395   
396   // 4. Check module catalogue server
397   for ( int i = 0; i < myAttempts ; i++ ) {
398     Locker locker( this );
399
400     setStep( current * myAttempts + i );
401
402     try {
403       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
404       CORBA::ORB_var orb = init( args.argc(), args.argv() );
405       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
406       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
407       NS.init_orb( orb );
408       CORBA::Object_var obj = NS.Resolve( "/Kernel/ModulCatalog" );
409       SALOME_ModuleCatalog::ModuleCatalog_var catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow( obj );
410       if ( !CORBA::is_nil( catalog ) ){
411         MESSAGE( "/Kernel/ModulCatalog is found" );
412         catalog->ping();
413         MESSAGE( "ModuleCatalog was activated" );
414         setStep( ++current * myAttempts );
415         break;
416       }
417     }
418     catch ( ServiceUnreachable& ) {
419       MESSAGE( "Caught exception: Naming Service unreachable." );
420       error = "Naming service unreachable";
421     }
422     catch ( CORBA::COMM_FAILURE& ) {
423       MESSAGE( "Caught CORBA::SystemException CommFailure." );
424       error = "Caught CORBA::SystemException CommFailure.";
425     }
426     catch ( CORBA::SystemException& ) {
427       MESSAGE( "Caught CORBA::SystemException." );
428       error = "Caught CORBA::SystemException.";
429     }
430     catch ( CORBA::Exception& ) {
431       MESSAGE( "Caught CORBA::Exception." );
432       error = "Caught CORBA::Exception.";
433     }
434     catch (...) {
435       MESSAGE( "Caught unknown exception." );
436       error = "Caught unknown exception.";
437     }
438
439     if ( i == myAttempts-1 ) {
440       setError( tr( "Module catalogue server is not found." ) + errfmt.arg( error ) );
441       return;
442     }
443   }
444
445   // 5. Check data server
446   for ( int i = 0; i < myAttempts ; i++ ) {
447     Locker locker( this );
448
449     setStep( current * myAttempts + i );
450
451     try {
452       ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
453       CORBA::ORB_var orb = init( args.argc(), args.argv() );
454       SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
455       ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
456       NS.init_orb( orb );
457       CORBA::Object_var obj = NS.Resolve( "/Kernel/Session" );
458       SALOME::Session_var session = SALOME::Session::_narrow( obj );
459       if ( !CORBA::is_nil( session ) ) {
460         MESSAGE( "/Kernel/Session is found" );
461         session->ping();
462         MESSAGE( "SALOME_Session was activated" );
463         setStep( ++current * myAttempts );
464         break;
465       }
466     }
467     catch ( ServiceUnreachable& ) {
468       MESSAGE( "Caught exception: Naming Service unreachable." );
469       error = "Naming service unreachable";
470     }
471     catch ( CORBA::COMM_FAILURE& ) {
472       MESSAGE( "Caught CORBA::SystemException CommFailure." );
473       error = "Caught CORBA::SystemException CommFailure.";
474     }
475     catch ( CORBA::SystemException& ) {
476       MESSAGE( "Caught CORBA::SystemException." );
477       error = "Caught CORBA::SystemException.";
478     }
479     catch ( CORBA::Exception& ) {
480       MESSAGE( "Caught CORBA::Exception." );
481       error = "Caught CORBA::Exception.";
482     }
483     catch (...) {
484       MESSAGE( "Caught unknown exception." );
485       error = "Caught unknown exception.";
486     }
487
488     if ( i == myAttempts-1 ) {
489       setError( tr( "Session server is not found." ) + errfmt.arg( error ) );
490       return;
491     }
492   }
493
494   // 6. Check C++ container
495   if ( myCheckCppContainer ) {
496     for ( int i = 0; i < myAttempts ; i++ ) {
497       Locker locker( this );
498       
499       setStep( current * myAttempts + i );
500
501       try {
502         ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
503         CORBA::ORB_var orb = init( args.argc(), args.argv() );
504         SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
505         ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
506         NS.init_orb( orb );
507         QString containerName = QString( "/Containers/%1/FactoryServer" ).arg( Kernel_Utils::GetHostname().c_str() );
508         CORBA::Object_var obj = NS.Resolve( containerName.toLatin1() );
509         Engines::Container_var FScontainer = Engines::Container::_narrow( obj );
510         if ( !CORBA::is_nil( FScontainer ) ) {
511           MESSAGE( containerName.toLatin1().constData() << " is found" );
512           FScontainer->ping();
513           MESSAGE( "FactoryServer container was activated" );
514           setStep( ++current * myAttempts );
515           break;
516         }
517       }
518       catch ( ServiceUnreachable& ) {
519         MESSAGE( "Caught exception: Naming Service unreachable." );
520         error = "Naming service unreachable";
521       }
522       catch ( CORBA::COMM_FAILURE& ) {
523         MESSAGE( "Caught CORBA::SystemException CommFailure." );
524         error = "Caught CORBA::SystemException CommFailure.";
525       }
526       catch ( CORBA::SystemException& ) {
527         MESSAGE( "Caught CORBA::SystemException." );
528         error = "Caught CORBA::SystemException.";
529       }
530       catch ( CORBA::Exception& ) {
531         MESSAGE( "Caught CORBA::Exception." );
532         error = "Caught CORBA::Exception.";
533       }
534       catch (...) {
535         MESSAGE( "Caught unknown exception." );
536         error = "Caught unknown exception.";
537       }
538       
539       if ( i == myAttempts-1 ) {
540         setError( tr( "C++ container is not found." ) + errfmt.arg( error ) );
541         return;
542       }
543     }
544   }
545
546   // 7. Check Python container
547   if ( myCheckPyContainer ) {
548     for ( int i = 0; i < myAttempts ; i++ ) {
549       Locker locker( this );
550       
551       setStep( current * myAttempts + i );
552
553       try {
554         ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
555         CORBA::ORB_var orb = init( args.argc(), args.argv() );
556         SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
557         ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
558         NS.init_orb( orb );
559         QString containerName = QString( "/Containers/%1/FactoryServerPy" ).arg( Kernel_Utils::GetHostname().c_str() );
560         CORBA::Object_var obj = NS.Resolve( containerName.toLatin1() );
561         Engines::Container_var FSPcontainer = Engines::Container::_narrow( obj );
562         if ( !CORBA::is_nil( FSPcontainer ) ) {
563           MESSAGE( containerName.toLatin1().constData() << " is found" );
564           FSPcontainer->ping();
565           MESSAGE("FactoryServerPy container was activated");
566           setStep( ++current * myAttempts );
567           break;
568         }
569       }
570       catch ( ServiceUnreachable& ) {
571         MESSAGE( "Caught exception: Naming Service unreachable." );
572         error = "Naming service unreachable";
573       }
574       catch ( CORBA::COMM_FAILURE& ) {
575         MESSAGE( "Caught CORBA::SystemException CommFailure." );
576         error = "Caught CORBA::SystemException CommFailure.";
577       }
578       catch ( CORBA::SystemException& ) {
579         MESSAGE( "Caught CORBA::SystemException." );
580         error = "Caught CORBA::SystemException.";
581       }
582       catch ( CORBA::Exception& ) {
583         MESSAGE( "Caught CORBA::Exception." );
584         error = "Caught CORBA::Exception.";
585       }
586       catch (...) {
587         MESSAGE( "Caught unknown exception." );
588         error = "Caught unknown exception.";
589       }
590
591       if ( i == myAttempts-1 ) {
592         setError( tr( "Python container is not found." ) + errfmt.arg( error ) );
593         return;
594       }
595     }
596   }
597
598   // 8. Check supervision container
599   if ( myCheckSVContainer ) {
600     for ( int i = 0; i < myAttempts ; i++ ) {
601       Locker locker( this );
602       
603       setStep( current * myAttempts + i );
604
605       try {
606         ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
607         CORBA::ORB_var orb = init( args.argc(), args.argv() );
608         SALOME_NamingService &NS = *SINGLETON_<SALOME_NamingService>::Instance();
609         ASSERT( SINGLETON_<SALOME_NamingService>::IsAlreadyExisting() );
610         NS.init_orb( orb );
611         QString containerName = QString( "/Containers/%1/SuperVisionContainer" ).arg( Kernel_Utils::GetHostname().c_str() );
612         CORBA::Object_var obj = NS.Resolve( containerName.toLatin1() );
613         Engines::Container_var SVcontainer = Engines::Container::_narrow( obj );
614         if ( !CORBA::is_nil( SVcontainer ) ) {
615           MESSAGE( containerName.toLatin1().constData() << " is found" );
616           SVcontainer->ping();
617           MESSAGE("SuperVisionContainer container was activated");
618           setStep( ++current * myAttempts );
619           break;
620         }
621       }
622       catch ( ServiceUnreachable& ) {
623         MESSAGE( "Caught exception: Naming Service unreachable." );
624         error = "Naming service unreachable";
625       }
626       catch ( CORBA::COMM_FAILURE& ) {
627         MESSAGE( "Caught CORBA::SystemException CommFailure." );
628         error = "Caught CORBA::SystemException CommFailure.";
629       }
630       catch ( CORBA::SystemException& ) {
631         MESSAGE( "Caught CORBA::SystemException." );
632         error = "Caught CORBA::SystemException.";
633       }
634       catch ( CORBA::Exception& ) {
635         MESSAGE( "Caught CORBA::Exception." );
636         error = "Caught CORBA::Exception.";
637       }
638       catch (...) {
639         MESSAGE( "Caught unknown exception." );
640         error = "Caught unknown exception.";
641       }
642     
643       if ( i == myAttempts-1 ) {
644         setError( tr( "Supervision container is not found." ) + errfmt.arg( error ) );
645         return;
646       }
647     }
648   }
649 }