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