1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SalomeApp_Engine_i : implementation of SalomeApp_Engine.idl
24 // File : SalomeApp_Engine_i.cxx
25 // Author : Alexander SLADKOV
27 #include "SalomeApp_Engine_i.hxx"
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>
36 #include <QApplication>
45 SalomeApp_Engine_i::SalomeApp_Engine_i( const char* theComponentName )
47 myComponentName = theComponentName;
48 MESSAGE("SalomeApp_Engine_i::SalomeApp_Engine_i(): myComponentName = " <<
49 myComponentName << ", this = " << this);
55 SalomeApp_Engine_i::~SalomeApp_Engine_i()
57 MESSAGE("SalomeApp_Engine_i::~SalomeApp_Engine_i(): myComponentName = " <<
58 myComponentName << ", this = " << this);
61 SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theComponent,
65 SALOMEDS::TMPFile_var aStreamFile = new SALOMEDS::TMPFile;
67 if (CORBA::is_nil(theComponent) || CORBA::is_nil(theComponent->GetStudy()))
68 return aStreamFile._retn();
70 const int studyId = theComponent->GetStudy()->StudyId();
72 // Get a temporary directory to store a file
73 //std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
75 if (myMap.count(studyId)) {
76 std::string componentName (theComponent->ComponentDataType());
78 // Error somewhere outside - Save() called with
79 // wrong SComponent instance
80 if ( myComponentName != componentName )
81 return aStreamFile._retn();
83 const ListOfFiles& listOfFiles = myMap[studyId];
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;
89 if (n > 0) { // there are some files, containing persistent data of the component
90 std::string aTmpDir = listOfFiles[0];
92 // Create a list to store names of created files
93 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
95 for (int i = 0; i < n; i++)
96 aSeq[i] = CORBA::string_dup(listOfFiles[i + 1].c_str());
98 // Convert a file to the byte stream
99 aStreamFile = SALOMEDS_Tool::PutFilesToStream(aTmpDir.c_str(), aSeq.in(), isMultiFile);
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);
106 return aStreamFile._retn();
109 CORBA::Boolean SalomeApp_Engine_i::Load (SALOMEDS::SComponent_ptr theComponent,
110 const SALOMEDS::TMPFile& theFile,
114 std::cout << "SalomeApp_Engine_i::Load() isMultiFile = " << isMultiFile << std::endl;
115 if (CORBA::is_nil(theComponent) || CORBA::is_nil(theComponent->GetStudy()))
118 // Error somewhere outside - Load() called with
119 // wrong SComponent instance
120 std::string componentName (theComponent->ComponentDataType());
121 if ( myComponentName != componentName )
124 const int studyId = theComponent->GetStudy()->StudyId();
126 // Create a temporary directory for the component's data files
127 std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
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);
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]);
141 SetListOfFiles(listOfFiles, studyId);
146 SalomeApp_Engine_i::ListOfFiles SalomeApp_Engine_i::GetListOfFiles (const int theStudyId)
148 ListOfFiles aListOfFiles;
150 if (myMap.find(theStudyId) != myMap.end())
152 aListOfFiles = myMap[theStudyId];
158 void SalomeApp_Engine_i::SetListOfFiles (const ListOfFiles& theListOfFiles,
159 const int theStudyId)
161 myMap[theStudyId] = theListOfFiles;
165 * DumpPython implementation for light modules
167 Engines::TMPFile* SalomeApp_Engine_i::DumpPython(CORBA::Object_ptr theStudy,
168 CORBA::Boolean isPublished,
169 CORBA::Boolean isMultiFile,
170 CORBA::Boolean& isValidScript)
172 MESSAGE("SalomeApp_Engine_i::DumpPython(): myComponentName = "<<
173 myComponentName << ", this = " << this);
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;
184 if (CORBA::is_nil(theStudy))
185 return aStreamFile._retn();
187 SALOMEDS::Study_var studyDS = SALOMEDS::Study::_narrow( theStudy );
188 const int studyId = studyDS->StudyId();
190 if (!myMap.count(studyId))
191 return aStreamFile._retn();
193 ListOfFiles listOfFiles = myMap[studyId];
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();
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();
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();
213 for (; aFIt != aFEnd; aFIt++){
214 QString aFileName( (*aFIt).c_str() );
215 if ( !aTmpDir.exists( aFileName ) ){
219 QFile aFile( aTmpDir.filePath( aFileName ) );
220 if ( !aFile.open( QIODevice::ReadOnly ) ){
224 aFilePaths.push_back( aTmpDir.filePath( aFileName ) );
225 aFileSizes.push_back( aFile.size() );
226 aBuffSize += aFileSizes.back();
231 if ( !aFilePaths.size() || !aBuffSize )
232 return aStreamFile._retn();
234 char* aBuffer = new char[aBuffSize + 1];
236 return aStreamFile._retn();
238 // Convert the file(s) to the byte stream, multiple files are simply
240 // TODO: imporve multi-script support if necessary...
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 ) ){
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 ){
255 return aStreamFile._retn();
262 // Here we should end up with empty aTmpDir
263 // TODO: Handle QDir::rmdir() error status somehow...
264 aTmpDir.rmdir( aTmpPath );
266 aBuffer[aBuffSize] = '\0';
267 CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer;
268 aStreamFile = new Engines::TMPFile(aBuffSize + 1, aBuffSize + 1, anOctetBuf, 1);
270 return aStreamFile._retn();
274 \return Component data type string for this instance of the engine
276 char* SalomeApp_Engine_i::ComponentDataType()
278 return const_cast<char*>( myComponentName.c_str() );
284 CORBA::ORB_var SalomeApp_Engine_i::orb()
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() );
296 PortableServer::POA_var SalomeApp_Engine_i::poa()
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 );
309 SALOME_NamingService* SalomeApp_Engine_i::namingService()
311 static SALOME_NamingService _ns(orb());
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
324 CORBA::Object_ptr SalomeApp_Engine_i::engineForComponent( const char* theComponentName,
327 CORBA::Object_var anEngine;
328 if ( !theComponentName || !strlen( theComponentName ) )
329 return anEngine._retn();
331 std::string aPath( "/SalomeAppEngine/" );
332 aPath += theComponentName;
333 anEngine = namingService()->Resolve( aPath.c_str() );
335 // Activating a new instance of the servant
336 if ( toCreate && CORBA::is_nil( anEngine ) ){
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() );
344 catch (CORBA::SystemException&) {
345 INFOS("Caught CORBA::SystemException.");
347 catch (CORBA::Exception&) {
348 INFOS("Caught CORBA::Exception.");
351 INFOS("Caught unknown exception.");
355 return anEngine._retn();
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 )
364 std::string SalomeApp_Engine_i::EngineIORForComponent( const char* theComponentName,
367 std::string anIOR( "" );
368 CORBA::Object_var anEngine = engineForComponent( theComponentName, toCreate );
369 if ( !CORBA::is_nil( anEngine ) )
371 CORBA::String_var objStr = orb()->object_to_string( anEngine.in() );
372 anIOR = std::string( objStr.in() );
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 )
382 SalomeApp_Engine_i* SalomeApp_Engine_i::GetInstance( const char* theComponentName,
385 SalomeApp_Engine_i* aServant = 0;
386 CORBA::Object_var anEngine = engineForComponent( theComponentName, toCreate );
387 if ( !CORBA::is_nil( anEngine ) )
389 PortableServer::Servant aServantBase = poa()->reference_to_servant( anEngine.in() );
390 aServant = dynamic_cast<SalomeApp_Engine_i*>( aServantBase );
392 MESSAGE("SalomeApp_Engine_i::GetInstance(): theComponentName = " <<
393 theComponentName << ", aServant = " << aServant);