Salome HOME
Merge branch 'master' into V9_dev
[modules/gui.git] / src / SalomeApp / SalomeApp_Engine_i.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 //  SalomeApp_Engine_i : implementation of SalomeApp_Engine.idl
24 //  File   : SalomeApp_Engine_i.cxx
25 //  Author : Alexander SLADKOV
26
27 #include "SalomeApp_Engine_i.h"
28 #include "SalomeApp_Application.h"
29
30 #include <SALOME_NamingService.hxx>
31 #include <SALOMEDS_Tool.hxx>
32 #include <Utils_ORB_INIT.hxx>
33 #include <Utils_SINGLETON.hxx>
34 #include <Utils_SALOME_Exception.hxx>
35 #include <utilities.h>
36
37 #include <QApplication>
38 #include <QDir>
39 #include <QFile>
40
41 #include <iostream>
42
43 /*!
44   Constructor
45 */
46 SalomeApp_Engine_i::SalomeApp_Engine_i( const char* theComponentName )
47 {
48   myComponentName = theComponentName;
49   MESSAGE("SalomeApp_Engine_i::SalomeApp_Engine_i(): myComponentName = " <<
50           myComponentName << ", this = " << this);
51 }
52
53 /*!
54   Destructor
55 */
56 SalomeApp_Engine_i::~SalomeApp_Engine_i()
57 {
58   MESSAGE("SalomeApp_Engine_i::~SalomeApp_Engine_i(): myComponentName = " << 
59           myComponentName << ", this = " << this);
60 }
61
62 SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theComponent,
63                                              const char* theURL,
64                                              bool isMultiFile)
65 {
66   SALOMEDS::TMPFile_var aStreamFile = new SALOMEDS::TMPFile;
67
68   if (CORBA::is_nil(theComponent))
69     return aStreamFile._retn();
70
71   // Get a temporary directory to store a file
72   //std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
73
74   std::string componentName (theComponent->ComponentDataType());
75
76   // Error somewhere outside - Save() called with
77   // wrong SComponent instance
78   if ( myComponentName != componentName )
79     return aStreamFile._retn();
80
81   // listOfFiles must contain temporary directory name in its first item
82   // and names of files (relatively the temporary directory) in the others
83   const int n = myListOfFiles.size() - 1;
84
85   if (n > 0) { // there are some files, containing persistent data of the component
86     std::string aTmpDir = myListOfFiles[0];
87
88     // Create a list to store names of created files
89     ListOfFiles aSeq;
90     aSeq.reserve(n);
91     for (int i = 0; i < n; i++)
92       aSeq.push_back(CORBA::string_dup(myListOfFiles[i + 1].c_str()));
93
94     // Convert a file to the byte stream
95     aStreamFile = SALOMEDS_Tool::PutFilesToStream(aTmpDir.c_str(), aSeq, isMultiFile);
96
97     // Remove the files and tmp directory, created by the component storage procedure
98     if (!isMultiFile) SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq, true);
99   }
100
101   return aStreamFile._retn();
102 }
103
104 CORBA::Boolean SalomeApp_Engine_i::Load (SALOMEDS::SComponent_ptr theComponent,
105                                          const SALOMEDS::TMPFile& theFile,
106                                          const char* theURL,
107                                          bool isMultiFile)
108 {
109   std::cout << "SalomeApp_Engine_i::Load() isMultiFile = " << isMultiFile << std::endl;
110   if (CORBA::is_nil(theComponent))
111     return false;
112
113   // Error somewhere outside - Load() called with
114   // wrong SComponent instance
115   std::string componentName (theComponent->ComponentDataType());
116   if ( myComponentName != componentName )
117     return false;
118
119   // Create a temporary directory for the component's data files
120   std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
121
122   // Convert the byte stream theStream to a files and place them in the tmp directory.
123   // The files and temporary directory must be deleted by the component loading procedure.
124   ListOfFiles aSeq =
125     SALOMEDS_Tool::PutStreamToFiles(theFile, aTmpDir.c_str(), isMultiFile);
126
127   // Store list of file names to be used by the component loading procedure
128   const int n = aSeq.size() + 1;
129   ListOfFiles listOfFiles (n);
130   listOfFiles[0] = aTmpDir;
131   for (int i = 1; i < n; i++)
132     listOfFiles[i] = std::string(aSeq[i - 1]);
133
134   SetListOfFiles(listOfFiles);
135
136   return true;
137 }
138
139 SalomeApp_Engine_i::ListOfFiles SalomeApp_Engine_i::GetListOfFiles()
140 {
141   return myListOfFiles;
142 }
143
144 void SalomeApp_Engine_i::SetListOfFiles (const ListOfFiles& theListOfFiles)
145 {
146   myListOfFiles = theListOfFiles;
147 }
148
149 /*! 
150  *  DumpPython implementation for light modules
151  */
152 Engines::TMPFile* SalomeApp_Engine_i::DumpPython(CORBA::Boolean isPublished,
153                                                                          CORBA::Boolean isMultiFile,
154                                                                          CORBA::Boolean& isValidScript)
155 {
156   MESSAGE("SalomeApp_Engine_i::DumpPython(): myComponentName = "<<
157           myComponentName << ", this = " << this);
158   
159   // Temporary solution: returning a non-empty sequence
160   // even if there's nothing to dump, to avoid crashes in SALOMEDS
161   // TODO: Improve SALOMEDSImpl_Study::DumpStudy() by skipping the components 
162   // with isValidScript == false, and initialize isValidScript by false below.
163   Engines::TMPFile_var aStreamFile = new Engines::TMPFile(1);
164   aStreamFile->length( 1 );
165   aStreamFile[0] = '\0';
166   isValidScript = true;
167
168   // listOfFiles must contain temporary directory name in its first item
169   // and names of files (relatively the temporary directory) in the others
170   if ( myListOfFiles.size() < 2 )
171     return aStreamFile._retn();
172
173   // there are some files, containing persistent data of the component
174   QString aTmpPath( myListOfFiles.front().c_str() );
175   QDir aTmpDir( aTmpPath );
176   if ( !aTmpDir.exists() )
177     return aStreamFile._retn();    
178
179   // Calculate file sizes
180   QStringList aFilePaths;
181   QList<qint64> aFileSizes;
182   qint64 aBuffSize = 0;
183   ListOfFiles::const_iterator aFIt  = myListOfFiles.begin();
184   ListOfFiles::const_iterator aFEnd = myListOfFiles.end();
185   aFIt++;
186   for (; aFIt != aFEnd; aFIt++){
187     QString aFileName( (*aFIt).c_str() );
188     if ( !aTmpDir.exists( aFileName ) ){
189       continue;
190     }
191
192     QFile aFile( aTmpDir.filePath( aFileName ) );
193     if ( !aFile.open( QIODevice::ReadOnly ) ){
194       continue;
195     }
196
197     aFilePaths.push_back( aTmpDir.filePath( aFileName ) );
198     aFileSizes.push_back( aFile.size() );
199     aBuffSize += aFileSizes.back();
200
201     aFile.close();
202   }
203
204   if ( !aFilePaths.size() || !aBuffSize )
205     return aStreamFile._retn(); 
206     
207   char* aBuffer = new char[aBuffSize + 1];
208   if ( !aBuffer )
209     return aStreamFile._retn();
210
211   // Convert the file(s) to the byte stream, multiple files are simply
212   // concatenated
213   // TODO: imporve multi-script support if necessary...
214   qint64 aCurrPos = 0;
215   QStringList::const_iterator aFileIt  = aFilePaths.begin();
216   QStringList::const_iterator aFileEnd = aFilePaths.end();
217   QList<qint64>::const_iterator   aSIt = aFileSizes.begin();
218   for ( ; aFileIt != aFileEnd; aFileIt++, aSIt++ ){
219     QFile aFile( aTmpDir.filePath( *aFileIt ) );
220     if ( !aFile.open( QIODevice::ReadOnly ) ){
221       continue;
222     }
223
224     // Incorrect size of file
225     // Do not remove the bad file to have some diagnostic means
226     if ( aFile.read( aBuffer + aCurrPos, *aSIt ) != *aSIt ){
227       aFile.close();      
228       return aStreamFile._retn();
229     }
230
231     aCurrPos += (*aSIt); 
232     aFile.remove();   
233   }
234
235   // Here we should end up with empty aTmpDir
236   // TODO: Handle QDir::rmdir() error status somehow...
237   aTmpDir.rmdir( aTmpPath );
238
239   aBuffer[aBuffSize] = '\0';
240   CORBA::Octet* anOctetBuf =  (CORBA::Octet*)aBuffer;
241   aStreamFile = new Engines::TMPFile(aBuffSize + 1, aBuffSize + 1, anOctetBuf, 1); 
242
243   return aStreamFile._retn();
244 }
245
246 /*!
247   \return Component data type string for this instance of the engine
248 */
249 char* SalomeApp_Engine_i::ComponentDataType()
250 {
251   return const_cast<char*>( myComponentName.c_str() );
252 }
253
254 /*!
255   \return Component version
256 */
257 char* SalomeApp_Engine_i::getVersion()
258 {
259   SalomeApp_Application::ModuleShortInfoList versions = SalomeApp_Application::getVersionInfo();
260   QString version;
261   SalomeApp_Application::ModuleShortInfo version_info;
262   foreach ( version_info, versions ) {
263     if ( SalomeApp_Application::moduleName( version_info.name ) == myComponentName.c_str() ) {
264       version = version_info.version;
265       break;
266     }
267   }
268   
269   return CORBA::string_dup( version.toLatin1().constData() );
270 }
271
272 /*!
273   \return 
274 */
275 CORBA::ORB_var SalomeApp_Engine_i::orb()
276 {
277   static CORBA::ORB_var _orb;
278
279   if ( CORBA::is_nil( _orb ) ) {
280     Qtx::CmdLineArgs args;
281     ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
282     _orb = init( args.argc(), args.argv() );
283   }
284
285   return _orb;
286 }
287
288 /*!
289   \return 
290 */
291 PortableServer::POA_var SalomeApp_Engine_i::poa()
292 {
293   static PortableServer::POA_var _poa;
294   if ( CORBA::is_nil( _poa ) ){
295     CORBA::Object_var obj = orb()->resolve_initial_references( "RootPOA" );
296     _poa = PortableServer::POA::_narrow( obj );
297   }
298   return _poa;
299 }
300
301 /*!
302   \return 
303 */
304 SALOME_NamingService* SalomeApp_Engine_i::namingService()
305 {
306   static SALOME_NamingService _ns(orb());
307   return &_ns;
308 }
309
310 /*!
311   Internal method, creates a CORBA engine for a light SALOME module
312   with the given "component data type" string,
313   activates it and registers in SALOME naming service with
314   /SalomeAppEngine/comp_data_type path. If the engine is already in the 
315   naming service, simply returns and object reference to it.
316   \param theComponentName - synthetic "component data type" used to identify a given light module
317   \return Object reference to the CORBA engine
318 */
319 CORBA::Object_ptr SalomeApp_Engine_i::EngineForComponent( const char* theComponentName,
320                                                           bool toCreate )
321 {
322   CORBA::Object_var anEngine;
323   if ( !theComponentName || !strlen( theComponentName ) )
324     return anEngine._retn();
325
326   if ( SalomeApp_Application::moduleTitle( theComponentName ).isEmpty() )
327     return anEngine._retn();
328
329   std::string aPath( "/SalomeAppEngine/" );
330   aPath += theComponentName;
331   anEngine = namingService()->Resolve( aPath.c_str() );
332
333   // Activating a new instance of the servant
334   if ( toCreate && CORBA::is_nil( anEngine ) ){
335     try {
336       SalomeApp_Engine_i* aServant    = new SalomeApp_Engine_i( theComponentName );
337       PortableServer::ObjectId_var id = poa()->activate_object( aServant );
338       anEngine = aServant->_this();
339       aServant->_remove_ref();
340       namingService()->Register( anEngine.in(), aPath.c_str() );
341     }
342     catch (CORBA::SystemException&) {
343       INFOS("Caught CORBA::SystemException.");
344     }
345     catch (CORBA::Exception&) {
346       INFOS("Caught CORBA::Exception.");
347     }
348     catch (...) {
349       INFOS("Caught unknown exception.");
350     }
351   }
352
353   return anEngine._retn();
354 }
355
356 /*!
357   \param theComponentName - synthetic "component data type" used to identify a given light module
358   \return IOR string for the CORBA engine for a light SALOME module
359   with the given "component data type" string
360   \sa GetInstance( const char* theComponentName )
361 */
362 std::string SalomeApp_Engine_i::EngineIORForComponent( const char* theComponentName,
363                                                        bool toCreate )
364 {
365   std::string anIOR( "" );
366   CORBA::Object_var anEngine = EngineForComponent( theComponentName, toCreate );
367   if ( !CORBA::is_nil( anEngine ) )
368   {
369     CORBA::String_var objStr = orb()->object_to_string( anEngine.in() );
370     anIOR = std::string( objStr.in() );
371   }
372   return anIOR;
373 }
374
375 /*!
376   \param theComponentName - synthetic "component data type" used to identify a given light module
377   \return A pointer to corresponding C++ engine instance, null means some internal problems.
378   \sa EngineIORForComponent( const char* theComponentName )
379 */
380 SalomeApp_Engine_i* SalomeApp_Engine_i::GetInstance( const char* theComponentName,
381                                                      bool toCreate )
382 {
383   SalomeApp_Engine_i* aServant = 0;
384   CORBA::Object_var anEngine = EngineForComponent( theComponentName, toCreate );
385   if ( !CORBA::is_nil( anEngine ) )
386   {
387     PortableServer::Servant aServantBase = poa()->reference_to_servant( anEngine.in() );
388     aServant = dynamic_cast<SalomeApp_Engine_i*>( aServantBase );
389   } 
390   MESSAGE("SalomeApp_Engine_i::GetInstance(): theComponentName = " <<
391           theComponentName << ", aServant = " << aServant);
392   return aServant;
393 }