Salome HOME
1d3af0a513c41506bf58ab43f4fbba5755c9c160
[modules/gui.git] / src / Session / SALOME_Session_Server.cxx
1 //  SALOME Session : implementation of Session.idl
2 //
3 //  Copyright (C) 2003  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. 
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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SALOME_Session_Server.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SALOME
27 //  $Header$
28
29 #include <Container_init_python.hxx>
30 #include "Utils_ORB_INIT.hxx"
31 #include "Utils_SINGLETON.hxx"
32 #include "SALOME_NamingService.hxx"
33 #include "SALOMETraceCollector.hxx"
34
35 #include <iostream>
36 #include <unistd.h>
37
38 #include <qdir.h>
39 #include <qfile.h>
40 #include <qapplication.h>
41 #include <qwaitcondition.h>
42
43 #include "Utils_SALOME_Exception.hxx"
44 #include "Utils_CorbaException.hxx"
45 #include "SALOME_Event.hxx"
46
47 #include <SALOMEconfig.h>
48 #include CORBA_SERVER_HEADER(SALOME_Session)
49 #include CORBA_SERVER_HEADER(SALOMEDS)
50
51 #include <utilities.h>
52 #include "Session_Session_i.hxx"
53 #include "Session_ServerLauncher.hxx"
54
55 #include "SUIT_Session.h"
56 #include "SUIT_Application.h"
57 #include "SUIT_MessageBox.h"
58
59
60 #include "SUIT_ExceptionHandler.h"
61 using namespace std;
62
63 extern "C" int HandleSignals(QApplication *theQApplication);
64
65 /*! - read arguments, define list of server to launch with their arguments.
66  *  - wait for naming service
67  *  - create and run a thread for launch of all servers
68  *  
69  */
70
71 //! CORBA server for SALOME Session
72 /*!
73  *  SALOME_Session Server launches a SALOME session servant.
74  *  The servant registers to the Naming Service.
75  *  See SALOME_Session.idl for interface specification.
76  *
77  *  Main services offered by the servant are:
78  *   - launch GUI
79  *   - stop Session (must be idle)
80  *   - get session state
81  */
82
83 QString salomeVersion()
84 {
85   QString path( ::getenv( "GUI_ROOT_DIR" ) );
86   if ( !path.isEmpty() )
87     path += QDir::separator();
88   path += QString( "bin/salome/VERSION" );
89
90   QFile vf( path );
91   if ( !vf.open( IO_ReadOnly ) )
92     return QString::null;
93
94   QString line;
95   vf.readLine( line, 1024 );
96   vf.close();
97
98   if ( line.isEmpty() )
99     return QString::null;
100
101   while ( !line.isEmpty() && line.at( line.length() - 1 ) == QChar( '\n' ) )
102     line.remove( line.length() - 1, 1 );
103
104   QString ver;
105   int idx = line.findRev( ":" );
106   if ( idx != -1 )
107     ver = line.mid( idx + 1 ).stripWhiteSpace();
108
109   return ver;
110 }
111
112 PyObject *salome_shared_modules_module = NULL;
113
114 void MessageOutput( QtMsgType type, const char *msg )
115 {
116   switch ( type ) {
117   case QtDebugMsg:
118     MESSAGE( "Debug: " << msg );
119     break;
120   case QtWarningMsg:
121     MESSAGE( "Warning: " << msg );
122     break;
123   case QtFatalMsg:
124     MESSAGE( "Fatal: " << msg );
125     break;
126   }
127 }
128
129 class SALOME_Session : public SUIT_Session
130 {
131 public:
132   SALOME_Session() : SUIT_Session() {}
133   virtual ~SALOME_Session() {}
134
135 protected:
136   virtual SUIT_ResourceMgr* createResourceMgr( const QString& appName ) const
137   {
138     SUIT_ResourceMgr* resMgr = new SUIT_ResourceMgr( appName, QString( "%1Config" ) );
139     resMgr->setVersion( salomeVersion() );
140     resMgr->setCurrentFormat( "xml" );
141     return resMgr;
142   }
143 };
144
145 class SALOME_QApplication : public QApplication 
146 {
147 public:
148   SALOME_QApplication( int& argc, char** argv ) : QApplication( argc, argv ) 
149   {
150     myHandler = 0;
151   }
152   
153   virtual bool notify( QObject* receiver, QEvent* e ) 
154   {
155     return myHandler ? myHandler->handle( receiver, e ) :
156                        QApplication::notify( receiver, e );
157   }
158   SUIT_ExceptionHandler*  handler() const { return myHandler; }
159   void setHandler( SUIT_ExceptionHandler* h ) { myHandler = h; }
160
161 private:
162   SUIT_ExceptionHandler*  myHandler;
163 };
164
165 int main(int argc, char **argv)
166 {
167   qInstallMsgHandler( MessageOutput );
168
169   /*
170   char* _argv_0[512];
171   strcpy( (char*)_argv_0, (char*)argv[0] );
172   */
173
174   // QApplication should be create before all other operations
175   // When uses QApplication::libraryPaths() (example, QFile::encodeName())
176   // qApp used for detection of the executable dir path.
177   SALOME_QApplication _qappl( argc, argv );
178   ASSERT( QObject::connect(&_qappl, SIGNAL( lastWindowClosed() ), &_qappl, SLOT( quit() ) ) );
179   QString path( ::getenv( "GUI_ROOT_DIR" ) );
180   if ( !path.isEmpty() )
181     path += QDir::separator();
182   path += QString( "bin/salome" );
183   _qappl.addLibraryPath( path );
184   _qappl.setStyle( "salome" );
185
186   /*
187     Python initialisation : only once
188   */
189
190   int _argc = 1;
191   char* _argv[] = {""};
192   KERNEL_PYTHON::init_python(_argc,_argv);
193   PyEval_RestoreThread(KERNEL_PYTHON::_gtstate);
194   if(!KERNEL_PYTHON::salome_shared_modules_module) // import only once
195     {
196       KERNEL_PYTHON::salome_shared_modules_module =
197         PyImport_ImportModule("salome_shared_modules");
198     }
199   if(!KERNEL_PYTHON::salome_shared_modules_module)
200     {
201       INFOS("salome_shared_modules_module == NULL");
202       PyErr_Print();
203       PyErr_Clear();
204     }
205   PyEval_ReleaseThread(KERNEL_PYTHON::_gtstate);
206
207   int result = -1;
208
209   // 1. create ORB, get RootPOA object, NamingService, etc.
210   ORB_INIT &init = *SINGLETON_<ORB_INIT>::Instance() ;
211   ASSERT(SINGLETON_<ORB_INIT>::IsAlreadyExisting()) ;
212   int orbArgc = 1;
213   CORBA::ORB_var &orb = init( orbArgc , argv ) ;
214   SALOMETraceCollector *myThreadTrace = SALOMETraceCollector::instance(orb);
215
216   try
217     {
218       SALOME_Event::GetSessionThread();
219
220       CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
221       PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
222
223       PortableServer::POAManager_var pman = poa->the_POAManager() ;
224       pman->activate() ;
225       INFOS("pman->activate()");
226
227       SALOME_NamingService *_NS = new SALOME_NamingService(orb);
228
229       // CORBA Servant Launcher
230       QMutex _GUIMutex ;
231       QWaitCondition _ServerLaunch;
232       _GUIMutex.lock();     // to block Launch server thread until wait(mutex)
233
234       // 2. activate embedded CORBA servers: Registry, SALOMEDS, etc.
235       Session_ServerLauncher* myServerLauncher
236         = new Session_ServerLauncher(argc, argv, orb, poa, &_GUIMutex, &_ServerLaunch);
237       myServerLauncher->start();
238
239       // 3. GUI activation
240       // Allow multiple activation/deactivation of GUI
241       //while ( 1 ) {
242         MESSAGE("waiting wakeAll()");
243         _ServerLaunch.wait(&_GUIMutex); // to be reseased by Launch server thread when ready:
244         // atomic operation lock - unlock on mutex
245         // unlock mutex: serverThread runs, calls  _ServerLaunch->wakeAll()
246         // this thread wakes up, and lock mutex
247
248         INFOS("Session activated, Launch IAPP...");
249         /*
250         int qArgc = 1;
251         argv[0] = (char*)_argv_0;
252         SALOME_QApplication* _qappl = new SALOME_QApplication( qArgc, argv );
253
254         QStringList lst = _qappl->libraryPaths();
255         for ( QStringList::const_iterator it = lst.begin(); it != lst.end(); ++it )
256           printf( "=====> Library path: %s\n", (*it).latin1() );
257
258         _qappl->setStyle( "salome" );
259
260         ASSERT ( QObject::connect(_qappl, SIGNAL(lastWindowClosed()), _qappl, SLOT(quit()) ) );
261         */
262         
263         INFOS("creation QApplication");
264         _GUIMutex.unlock();
265
266         // 3.1 SUIT_Session creation    
267         SUIT_Session* aGUISession = new SALOME_Session();
268         INFOS("creation SUIT_Application");
269
270         SCRUTE(_NS);
271
272         // 3.3 run GUI loop
273         // T2.12 - catch exceptions thrown on attempts to modified a locked study
274         while (1) {
275           try 
276           {
277             MESSAGE("run(): starting the main event loop");
278
279             // 3.2 load SalomeApp dynamic library
280             SUIT_Application* aGUIApp = aGUISession->startApplication( "SalomeApp", 0, 0 );
281             if ( aGUIApp ) 
282             {
283               _qappl.setHandler( aGUISession->handler() ); // after loading SalomeApp application
284                                                             // aGUISession contains SalomeApp_ExceptionHandler
285               result = _qappl.exec();
286             }
287             break;
288           }
289           catch (SALOME::SALOME_Exception& e)
290           {
291             INFOS("run(): SALOME_Exception was caught!");
292             QApplication::restoreOverrideCursor();
293             SUIT_MessageBox::warn1 ( 0,
294                                     QObject::tr("WRN_WARNING"), 
295                                     QObject::tr("SALOME_Exception was caught!"),
296                                     QObject::tr("BUT_OK") );
297             //QtCatchCorbaException(e);
298           }
299           catch(SALOMEDS::StudyBuilder::LockProtection&)
300           {
301             INFOS("run(): An attempt to modify a locked study has not been handled by QAD_Operation");
302             QApplication::restoreOverrideCursor();
303             SUIT_MessageBox::warn1 ( 0,
304                                     QObject::tr("WRN_WARNING"), 
305                                     QObject::tr("WRN_STUDY_LOCKED"),
306                                     QObject::tr("BUT_OK") );
307           }
308           catch (const CORBA::Exception& e)
309           {
310             CORBA::Any tmp;
311             tmp<<= e;
312             CORBA::TypeCode_var tc = tmp.type();
313             const char *p = tc->name();
314             INFOS ("run(): CORBA exception of the kind : "<<p<< " is caught");
315
316             QApplication::restoreOverrideCursor();
317             SUIT_MessageBox::error1 ( 0,
318                                      QObject::tr("ERR_ERROR"), 
319                                      QObject::tr("ERR_APP_EXCEPTION")
320                                      + QObject::tr(" CORBA exception ") + QObject::tr(p),
321                                      QObject::tr("BUT_OK") );
322           }
323           catch(exception& e)
324           {
325             INFOS("run(): An exception has been caught");
326             QApplication::restoreOverrideCursor();
327             SUIT_MessageBox::error1 ( 0,
328                                      QObject::tr("ERR_ERROR"), 
329                                      QObject::tr("ERR_APP_EXCEPTION")+ "\n" +QObject::tr(e.what()),
330                                      QObject::tr("BUT_OK") );
331           }
332           catch(...)
333           {
334             INFOS("run(): An exception has been caught");
335             QApplication::restoreOverrideCursor();
336             SUIT_MessageBox::error1 ( 0,
337                                      QObject::tr("ERR_ERROR"), 
338                                      QObject::tr("ERR_APP_EXCEPTION"),
339                                      QObject::tr("BUT_OK") );
340           }
341         }
342 //}  end of "outer" while( 1 )
343
344       // Prepare _GUIMutex for a new GUI activation
345       //_GUIMutex.lock(); 
346         //      }
347
348       //orb->shutdown(0);
349       //myServerLauncher->KillAll();
350     }
351   catch (SALOME_Exception& e)
352     {
353       INFOS("run(): SALOME::SALOME_Exception is caught: "<<e.what());
354     }
355   catch (CORBA::SystemException& e)
356     {
357       INFOS("Caught CORBA::SystemException.");
358     }
359   catch (CORBA::Exception& e)
360     {
361       INFOS("Caught CORBA::Exception.");
362       CORBA::Any tmp;
363       tmp<<= e;
364       CORBA::TypeCode_var tc = tmp.type();
365       const char *p = tc->name();
366       INFOS ("run(): CORBA exception of the kind : "<<p<< " is caught");
367     }
368   catch(exception& e)
369     {
370       INFOS("run(): An exception has been caught: " <<e.what());
371     }
372   catch (...)
373     {
374       INFOS("Caught unknown exception.");
375     }
376   delete myThreadTrace;
377   return result ;
378 }