1 // Copyright (C) 2007-2016 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, or (at your option) any later version.
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.h"
28 #include "SalomeApp_Application.h"
29 #include "SalomeApp_Study.h"
30 #include "SUIT_Session.h"
31 #include "CAM_Module.h"
32 #include "LightApp_DataModel.h"
34 #include <SALOME_NamingService.hxx>
35 #include <SALOMEDS_Tool.hxx>
36 #include <Utils_ORB_INIT.hxx>
37 #include <Utils_SINGLETON.hxx>
38 #include <Utils_SALOME_Exception.hxx>
39 #include <utilities.h>
41 #include <QApplication>
49 SalomeApp_Study* getStudyById( int id )
51 SalomeApp_Study* study = 0;
52 QList<SUIT_Application*> apps = SUIT_Session::session()->applications();
53 for ( int i = 0; i < apps.count() && !study; i++ )
55 SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study*>( apps[i]->activeStudy() );
56 if ( appStudy && appStudy->id() == id )
66 SalomeApp_Engine_i::SalomeApp_Engine_i( const char* theComponentName )
67 : myComponentName( theComponentName )
69 MESSAGE("SalomeApp_Engine_i::SalomeApp_Engine_i(): myComponentName = " <<
70 qPrintable( myComponentName ) << ", this = " << this);
76 SalomeApp_Engine_i::~SalomeApp_Engine_i()
78 MESSAGE("SalomeApp_Engine_i::~SalomeApp_Engine_i(): myComponentName = " <<
79 qPrintable( myComponentName ) << ", this = " << this);
82 SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theComponent,
86 SALOMEDS::TMPFile_var aStreamFile = new SALOMEDS::TMPFile;
88 if ( CORBA::is_nil(theComponent) || CORBA::is_nil( theComponent->GetStudy() ) )
89 return aStreamFile._retn();
92 QString componentName = theComponent->ComponentDataType();
93 // Error somewhere outside - Save() called with wrong SComponent instance
94 if ( myComponentName != componentName )
95 return aStreamFile._retn();
98 const int studyId = theComponent->GetStudy()->StudyId();
100 bool manuallySaved = false;
102 if ( !myMap.count( studyId ) ) {
103 // Save was probably called from outside GUI, so SetListOfFiles was not called!
104 // Try to get list of files from directly from data model
106 MESSAGE("SalomeApp_Engine_i::Save(): myComponentName = " <<
107 qPrintable( myComponentName ) <<
108 "it seems Save() was called from outside GUI" );
111 SalomeApp_Study* study = getStudyById( studyId );
113 return aStreamFile._retn();
114 QString url = QString::fromStdString(study->studyDS()->URL());
116 SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( study->application() );
118 return aStreamFile._retn();
120 CAM_Module* module = app->module( SalomeApp_Application::moduleTitle( componentName ) );
121 if ( !module ) // load module???
122 return aStreamFile._retn();
124 LightApp_DataModel* dataModel = dynamic_cast<LightApp_DataModel*>( module->dataModel() );
126 return aStreamFile._retn();
128 QStringList dataFiles;
129 // we use 'url' instead of 'theURL' as latter normally contains path to the tmp dir,
130 // but not actual study's URL
131 dataModel->saveAs( url, study, dataFiles );
132 std::vector<std::string> names;
133 foreach ( QString name, dataFiles ) {
134 if ( !name.isEmpty() )
135 names.push_back(name.toUtf8().data());
137 SetListOfFiles( names, studyId );
138 manuallySaved = true;
141 // Get a temporary directory to store a file
142 //std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
144 if ( myMap.count( studyId ) ) {
146 const ListOfFiles& listOfFiles = myMap[studyId];
148 // listOfFiles must contain temporary directory name in its first item
149 // and names of files (relatively the temporary directory) in the others
150 const int n = listOfFiles.size() - 1;
152 if (n > 0) { // there are some files, containing persistent data of the component
153 std::string aTmpDir = listOfFiles[0];
155 // Create a list to store names of created files
156 SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames;
158 for (int i = 0; i < n; i++)
159 aSeq[i] = CORBA::string_dup(listOfFiles[i + 1].c_str());
161 // Convert a file to the byte stream
162 aStreamFile = SALOMEDS_Tool::PutFilesToStream(aTmpDir.c_str(), aSeq.in(), isMultiFile);
164 // Remove the files and tmp directory, created by the component storage procedure
165 if (!isMultiFile) SALOMEDS_Tool::RemoveTemporaryFiles(aTmpDir.c_str(), aSeq.in(), true);
170 SetListOfFiles( ListOfFiles(), studyId );
172 return aStreamFile._retn();
175 CORBA::Boolean SalomeApp_Engine_i::Load (SALOMEDS::SComponent_ptr theComponent,
176 const SALOMEDS::TMPFile& theFile,
180 std::cout << "SalomeApp_Engine_i::Load() isMultiFile = " << isMultiFile << std::endl;
181 if (CORBA::is_nil(theComponent) || CORBA::is_nil(theComponent->GetStudy()))
184 // Error somewhere outside - Load() called with
185 // wrong SComponent instance
186 QString componentName = theComponent->ComponentDataType();
187 if ( myComponentName != componentName )
190 const int studyId = theComponent->GetStudy()->StudyId();
192 // Create a temporary directory for the component's data files
193 std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
195 // Convert the byte stream theStream to a files and place them in the tmp directory.
196 // The files and temporary directory must be deleted by the component loading procedure.
197 SALOMEDS::ListOfFileNames_var aSeq =
198 SALOMEDS_Tool::PutStreamToFiles(theFile, aTmpDir.c_str(), isMultiFile);
200 // Store list of file names to be used by the component loading procedure
201 const int n = aSeq->length() + 1;
202 ListOfFiles listOfFiles (n);
203 listOfFiles[0] = aTmpDir;
204 for (int i = 1; i < n; i++)
205 listOfFiles[i] = std::string(aSeq[i - 1]);
207 SetListOfFiles(listOfFiles, studyId);
212 SalomeApp_Engine_i::ListOfFiles SalomeApp_Engine_i::GetListOfFiles (const int theStudyId)
214 ListOfFiles aListOfFiles;
216 if (myMap.find(theStudyId) != myMap.end())
218 aListOfFiles = myMap[theStudyId];
224 void SalomeApp_Engine_i::SetListOfFiles (const ListOfFiles& theListOfFiles,
225 const int theStudyId)
227 if ( theListOfFiles.empty() )
228 myMap.erase( theStudyId );
230 myMap[theStudyId] = theListOfFiles;
234 * DumpPython implementation for light modules
236 Engines::TMPFile* SalomeApp_Engine_i::DumpPython(CORBA::Object_ptr theStudy,
237 CORBA::Boolean isPublished,
238 CORBA::Boolean isMultiFile,
239 CORBA::Boolean& isValidScript)
241 MESSAGE("SalomeApp_Engine_i::DumpPython(): myComponentName = "<<
242 qPrintable( myComponentName ) << ", this = " << this);
244 // Temporary solution: returning a non-empty sequence
245 // even if there's nothing to dump, to avoid crashes in SALOMEDS
246 // TODO: Improve SALOMEDSImpl_Study::DumpStudy() by skipping the components
247 // with isValidScript == false, and initialize isValidScript by false below.
248 Engines::TMPFile_var aStreamFile = new Engines::TMPFile(1);
249 aStreamFile->length( 1 );
250 aStreamFile[0] = '\0';
251 isValidScript = true;
253 if (CORBA::is_nil(theStudy))
254 return aStreamFile._retn();
256 SALOMEDS::Study_var studyDS = SALOMEDS::Study::_narrow( theStudy );
257 const int studyId = studyDS->StudyId();
259 if (!myMap.count(studyId))
260 return aStreamFile._retn();
262 ListOfFiles listOfFiles = myMap[studyId];
264 // listOfFiles must contain temporary directory name in its first item
265 // and names of files (relatively the temporary directory) in the others
266 if ( listOfFiles.size() < 2 )
267 return aStreamFile._retn();
269 // there are some files, containing persistent data of the component
270 QString aTmpPath( listOfFiles.front().c_str() );
271 QDir aTmpDir( aTmpPath );
272 if ( !aTmpDir.exists() )
273 return aStreamFile._retn();
275 // Calculate file sizes
276 QStringList aFilePaths;
277 QList<qint64> aFileSizes;
278 qint64 aBuffSize = 0;
279 ListOfFiles::const_iterator aFIt = listOfFiles.begin();
280 ListOfFiles::const_iterator aFEnd = listOfFiles.end();
282 for (; aFIt != aFEnd; aFIt++){
283 QString aFileName( (*aFIt).c_str() );
284 if ( !aTmpDir.exists( aFileName ) ){
288 QFile aFile( aTmpDir.filePath( aFileName ) );
289 if ( !aFile.open( QIODevice::ReadOnly ) ){
293 aFilePaths.push_back( aTmpDir.filePath( aFileName ) );
294 aFileSizes.push_back( aFile.size() );
295 aBuffSize += aFileSizes.back();
300 if ( !aFilePaths.size() || !aBuffSize )
301 return aStreamFile._retn();
303 char* aBuffer = new char[aBuffSize + 1];
305 return aStreamFile._retn();
307 // Convert the file(s) to the byte stream, multiple files are simply
309 // TODO: imporve multi-script support if necessary...
311 QStringList::const_iterator aFileIt = aFilePaths.begin();
312 QStringList::const_iterator aFileEnd = aFilePaths.end();
313 QList<qint64>::const_iterator aSIt = aFileSizes.begin();
314 for ( ; aFileIt != aFileEnd; aFileIt++, aSIt++ ){
315 QFile aFile( aTmpDir.filePath( *aFileIt ) );
316 if ( !aFile.open( QIODevice::ReadOnly ) ){
320 // Incorrect size of file
321 // Do not remove the bad file to have some diagnostic means
322 if ( aFile.read( aBuffer + aCurrPos, *aSIt ) != *aSIt ){
324 return aStreamFile._retn();
331 // Here we should end up with empty aTmpDir
332 // TODO: Handle QDir::rmdir() error status somehow...
333 aTmpDir.rmdir( aTmpPath );
335 aBuffer[aBuffSize] = '\0';
336 CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer;
337 aStreamFile = new Engines::TMPFile(aBuffSize + 1, aBuffSize + 1, anOctetBuf, 1);
339 return aStreamFile._retn();
343 \return Component data type string for this instance of the engine
345 char* SalomeApp_Engine_i::ComponentDataType()
347 return CORBA::string_dup( myComponentName.toLatin1().constData() );
351 \return Component version
353 char* SalomeApp_Engine_i::getVersion()
355 SalomeApp_Application::ModuleShortInfoList versions = SalomeApp_Application::getVersionInfo();
357 SalomeApp_Application::ModuleShortInfo version_info;
358 foreach ( version_info, versions ) {
359 if ( SalomeApp_Application::moduleName( version_info.name ) == myComponentName ) {
360 version = version_info.version;
365 return CORBA::string_dup( version.toLatin1().constData() );
371 CORBA::ORB_var SalomeApp_Engine_i::orb()
373 static CORBA::ORB_var _orb;
375 if ( CORBA::is_nil( _orb ) ) {
376 Qtx::CmdLineArgs args;
377 ORB_INIT& init = *SINGLETON_<ORB_INIT>::Instance();
378 _orb = init( args.argc(), args.argv() );
387 PortableServer::POA_var SalomeApp_Engine_i::poa()
389 static PortableServer::POA_var _poa;
390 if ( CORBA::is_nil( _poa ) ){
391 CORBA::Object_var obj = orb()->resolve_initial_references( "RootPOA" );
392 _poa = PortableServer::POA::_narrow( obj );
400 SALOME_NamingService* SalomeApp_Engine_i::namingService()
402 static SALOME_NamingService _ns(orb());
407 Internal method, creates a CORBA engine for a light SALOME module
408 with the given "component data type" string,
409 activates it and registers in SALOME naming service with
410 /SalomeAppEngine/comp_data_type path. If the engine is already in the
411 naming service, simply returns and object reference to it.
412 \param theComponentName - synthetic "component data type" used to identify a given light module
413 \return Object reference to the CORBA engine
415 CORBA::Object_ptr SalomeApp_Engine_i::EngineForComponent( const char* theComponentName,
418 CORBA::Object_var anEngine;
419 if ( !theComponentName || !strlen( theComponentName ) )
420 return anEngine._retn();
422 if ( SalomeApp_Application::moduleTitle( theComponentName ).isEmpty() )
423 return anEngine._retn();
425 std::string aPath( "/SalomeAppEngine/" );
426 aPath += theComponentName;
427 anEngine = namingService()->Resolve( aPath.c_str() );
429 // Activating a new instance of the servant
430 if ( toCreate && CORBA::is_nil( anEngine ) ){
432 SalomeApp_Engine_i* aServant = new SalomeApp_Engine_i( theComponentName );
433 PortableServer::ObjectId_var id = poa()->activate_object( aServant );
434 anEngine = aServant->_this();
435 aServant->_remove_ref();
436 namingService()->Register( anEngine.in(), aPath.c_str() );
438 catch (CORBA::SystemException&) {
439 INFOS("Caught CORBA::SystemException.");
441 catch (CORBA::Exception&) {
442 INFOS("Caught CORBA::Exception.");
445 INFOS("Caught unknown exception.");
449 return anEngine._retn();
453 \param theComponentName - synthetic "component data type" used to identify a given light module
454 \return IOR string for the CORBA engine for a light SALOME module
455 with the given "component data type" string
456 \sa GetInstance( const char* theComponentName )
458 std::string SalomeApp_Engine_i::EngineIORForComponent( const char* theComponentName,
461 std::string anIOR( "" );
462 CORBA::Object_var anEngine = EngineForComponent( theComponentName, toCreate );
463 if ( !CORBA::is_nil( anEngine ) )
465 CORBA::String_var objStr = orb()->object_to_string( anEngine.in() );
466 anIOR = std::string( objStr.in() );
472 \param theComponentName - synthetic "component data type" used to identify a given light module
473 \return A pointer to corresponding C++ engine instance, null means some internal problems.
474 \sa EngineIORForComponent( const char* theComponentName )
476 SalomeApp_Engine_i* SalomeApp_Engine_i::GetInstance( const char* theComponentName,
479 SalomeApp_Engine_i* aServant = 0;
480 CORBA::Object_var anEngine = EngineForComponent( theComponentName, toCreate );
481 if ( !CORBA::is_nil( anEngine ) )
483 PortableServer::Servant aServantBase = poa()->reference_to_servant( anEngine.in() );
484 aServant = dynamic_cast<SalomeApp_Engine_i*>( aServantBase );
486 MESSAGE("SalomeApp_Engine_i::GetInstance(): theComponentName = " <<
487 theComponentName << ", aServant = " << aServant);