1 // Copyright (C) 2007-2021 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 <ArgvKeeper.hxx>
38 #include <Utils_SALOME_Exception.hxx>
39 #include <utilities.h>
41 #include <QApplication>
50 SalomeApp_Engine_i::SalomeApp_Engine_i( const char* theComponentName )
51 : myKeepFiles( false ), myComponentName( theComponentName )
53 MESSAGE("SalomeApp_Engine_i::SalomeApp_Engine_i(): myComponentName = " <<
54 qPrintable( myComponentName ) << ", this = " << this);
60 SalomeApp_Engine_i::~SalomeApp_Engine_i()
62 MESSAGE("SalomeApp_Engine_i::~SalomeApp_Engine_i(): myComponentName = " <<
63 qPrintable( myComponentName ) << ", this = " << this);
66 SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theComponent,
67 const char* /*theURL*/,
70 SALOMEDS::TMPFile_var aStreamFile = new SALOMEDS::TMPFile;
73 if (CORBA::is_nil(theComponent))
74 return aStreamFile._retn();
77 QString componentName (theComponent->ComponentDataType());
79 // Error somewhere outside - Save() called with wrong SComponent instance
80 if ( myComponentName != componentName )
81 return aStreamFile._retn();
83 // Get a temporary directory to store a file
84 //std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
86 bool manuallySaved = false;
88 if ( GetListOfFiles(0).empty() ) // 0 means persistence file
91 // Save was probably called from outside GUI, so SetListOfFiles was not called!
92 // Try to get list of files from directly from data model
94 MESSAGE("SalomeApp_Engine_i::Save(): myComponentName = " <<
95 qPrintable( myComponentName ) <<
96 "it seems Save() was called from outside GUI" );
99 SalomeApp_Application* app =
100 dynamic_cast<SalomeApp_Application*>(SUIT_Session::session()->activeApplication());
102 return aStreamFile._retn();
105 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() );
108 return aStreamFile._retn();
109 QString url = QString::fromStdString(study->studyDS()->URL());
112 CAM_Module* module = app->module( SalomeApp_Application::moduleTitle( componentName ) );
113 if ( !module ) // load module???
114 return aStreamFile._retn();
116 LightApp_DataModel* dataModel = dynamic_cast<LightApp_DataModel*>( module->dataModel() );
118 return aStreamFile._retn();
120 QStringList dataFiles;
121 // we use 'url' instead of 'theURL' as latter normally contains path to the tmp dir,
122 // but not actual study's URL
123 dataModel->saveAs( url, study, dataFiles );
124 std::vector<std::string> names;
125 foreach ( QString name, dataFiles ) {
126 if ( !name.isEmpty() )
127 names.push_back(name.toUtf8().data());
129 SetListOfFiles( 0, names ); // 0 means persistence file
130 manuallySaved = true;
133 // Get a temporary directory to store a file
134 //std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
136 // listOfFiles must contain temporary directory name in its first item
137 // and names of files (relatively the temporary directory) in the others
138 ListOfFiles listOfFiles = GetListOfFiles( 0 ); // 0 means persistence file
139 const int n = (int)listOfFiles.size() - 1; //!< TODO: conversion from size_t to int
141 if (n > 0) { // there are some files, containing persistent data of the component
142 std::string aTmpDir = listOfFiles[0];
144 // Create a list to store names of created files
147 for (int i = 0; i < n; i++)
148 aSeq.push_back(CORBA::string_dup(listOfFiles[i + 1].c_str()));
150 // Convert a file to the byte stream
151 aStreamFile = SALOMEDS_Tool::PutFilesToStream(aTmpDir.c_str(), aSeq, isMultiFile);
153 // Remove the files and tmp directory, created by the component storage procedure
154 SalomeApp_Application* app =
155 dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
156 SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() );
157 study->RemoveTemporaryFiles( myComponentName.toStdString().c_str(), isMultiFile );
161 SetListOfFiles(0, ListOfFiles()); // 0 means persistence file
163 return aStreamFile._retn();
166 CORBA::Boolean SalomeApp_Engine_i::Load (SALOMEDS::SComponent_ptr theComponent,
167 const SALOMEDS::TMPFile& theFile,
171 std::cout << "SalomeApp_Engine_i::Load() isMultiFile = " << isMultiFile << std::endl;
172 if (CORBA::is_nil(theComponent))
175 // Error somewhere outside - Load() called with
176 // wrong SComponent instance
177 QString componentName = theComponent->ComponentDataType();
178 if ( myComponentName != componentName )
181 // Create a temporary directory for the component's data files
182 std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir();
184 // Convert the byte stream theStream to a files and place them in the tmp directory.
185 // The files and temporary directory must be deleted by the component loading procedure.
187 SALOMEDS_Tool::PutStreamToFiles(theFile, aTmpDir.c_str(), isMultiFile);
189 // Store list of file names to be used by the component loading procedure
190 const int n = (int)aSeq.size() + 1; //!< TODO: conversion from size_t to int
191 ListOfFiles listOfFiles (n);
192 listOfFiles[0] = aTmpDir;
193 for (int i = 1; i < n; i++)
194 listOfFiles[i] = std::string(aSeq[i - 1]);
196 SetListOfFiles(0, listOfFiles); // 0 means persistence file
202 SalomeApp_Engine_i::ListOfFiles SalomeApp_Engine_i::GetListOfFiles(int type)
204 return myListOfFiles.count(type) ? myListOfFiles[type] : ListOfFiles();
207 void SalomeApp_Engine_i::SetListOfFiles (int type, const ListOfFiles& theListOfFiles)
209 myListOfFiles[type] = theListOfFiles;
213 * DumpPython implementation for light modules
215 Engines::TMPFile* SalomeApp_Engine_i::DumpPython(CORBA::Boolean /*isPublished*/,
216 CORBA::Boolean /*isMultiFile*/,
217 CORBA::Boolean& isValidScript)
219 MESSAGE("SalomeApp_Engine_i::DumpPython(): myComponentName = "<<
220 qPrintable( myComponentName ) << ", this = " << this);
222 // Temporary solution: returning a non-empty sequence
223 // even if there's nothing to dump, to avoid crashes in SALOMEDS
224 // TODO: Improve SALOMEDSImpl_Study::DumpStudy() by skipping the components
225 // with isValidScript == false, and initialize isValidScript by false below.
226 Engines::TMPFile_var aStreamFile = new Engines::TMPFile(1);
227 aStreamFile->length( 1 );
228 aStreamFile[0] = '\0';
229 isValidScript = true;
231 ListOfFiles listOfFiles = GetListOfFiles( 1 ); // 1 means dump file
233 // listOfFiles must contain temporary directory name in its first item
234 // and names of files (relatively the temporary directory) in the others
235 if ( listOfFiles.size() < 2 )
236 return aStreamFile._retn();
238 // there are some files, containing persistent data of the component
239 QString aTmpPath( listOfFiles.front().c_str() );
240 QDir aTmpDir( aTmpPath );
241 if ( !aTmpDir.exists() )
242 return aStreamFile._retn();
244 // Calculate file sizes
245 QStringList aFilePaths;
246 QList<qint64> aFileSizes;
247 qint64 aBuffSize = 0;
248 ListOfFiles::const_iterator aFIt = listOfFiles.begin();
249 ListOfFiles::const_iterator aFEnd = listOfFiles.end();
251 for (; aFIt != aFEnd; aFIt++){
252 QString aFileName( (*aFIt).c_str() );
253 if ( !aTmpDir.exists( aFileName ) ){
257 QFile aFile( aTmpDir.filePath( aFileName ) );
258 if ( !aFile.open( QIODevice::ReadOnly ) ){
262 aFilePaths.push_back( aTmpDir.filePath( aFileName ) );
263 aFileSizes.push_back( aFile.size() );
264 aBuffSize += aFileSizes.back();
269 if ( !aFilePaths.size() || !aBuffSize )
270 return aStreamFile._retn();
272 char* aBuffer = new char[aBuffSize + 1];
274 return aStreamFile._retn();
276 // Convert the file(s) to the byte stream, multiple files are simply
278 // TODO: imporve multi-script support if necessary...
280 QStringList::const_iterator aFileIt = aFilePaths.begin();
281 QStringList::const_iterator aFileEnd = aFilePaths.end();
282 QList<qint64>::const_iterator aSIt = aFileSizes.begin();
283 for ( ; aFileIt != aFileEnd; aFileIt++, aSIt++ ){
284 QFile aFile( aTmpDir.filePath( *aFileIt ) );
285 if ( !aFile.open( QIODevice::ReadOnly ) ){
289 // Incorrect size of file
290 // Do not remove the bad file to have some diagnostic means
291 if ( aFile.read( aBuffer + aCurrPos, *aSIt ) != *aSIt ){
293 return aStreamFile._retn();
300 // Here we should end up with empty aTmpDir
301 // TODO: Handle QDir::rmdir() error status somehow...
302 aTmpDir.rmdir( aTmpPath );
304 aBuffer[aBuffSize] = '\0';
305 CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer;
306 aStreamFile = new Engines::TMPFile(aBuffSize + 1, aBuffSize + 1, anOctetBuf, 1);
308 return aStreamFile._retn();
312 \return Component data type string for this instance of the engine
314 char* SalomeApp_Engine_i::ComponentDataType()
316 return CORBA::string_dup( myComponentName.toLatin1().constData() );
320 \return Component version
322 char* SalomeApp_Engine_i::getVersion()
324 SalomeApp_Application::ModuleShortInfoList versions = SalomeApp_Application::getVersionInfo();
326 SalomeApp_Application::ModuleShortInfo version_info;
327 foreach ( version_info, versions ) {
328 if ( SalomeApp_Application::moduleName( version_info.name ) == myComponentName ) {
329 version = version_info.version;
334 return CORBA::string_dup( version.toLatin1().constData() );
340 CORBA::ORB_var SalomeApp_Engine_i::orb()
342 static CORBA::ORB_var _orb;
344 if ( CORBA::is_nil( _orb ) ) {
345 Qtx::CmdLineArgs args;
346 SetArgcArgv( args.argc(), args.argv() );
347 _orb = KERNEL::GetRefToORB();
356 PortableServer::POA_var SalomeApp_Engine_i::poa()
358 static PortableServer::POA_var _poa;
359 if ( CORBA::is_nil( _poa ) ){
360 CORBA::Object_var obj = orb()->resolve_initial_references( "RootPOA" );
361 _poa = PortableServer::POA::_narrow( obj );
369 SALOME_NamingService_Abstract* SalomeApp_Engine_i::namingService()
371 return SalomeApp_Application::namingService();
375 Internal method, creates a CORBA engine for a light SALOME module
376 with the given "component data type" string,
377 activates it and registers in SALOME naming service with
378 /SalomeAppEngine/comp_data_type path. If the engine is already in the
379 naming service, simply returns and object reference to it.
380 \param theComponentName - synthetic "component data type" used to identify a given light module
381 \return Object reference to the CORBA engine
383 CORBA::Object_ptr SalomeApp_Engine_i::EngineForComponent( const char* theComponentName,
386 CORBA::Object_var anEngine;
387 if ( !theComponentName || !strlen( theComponentName ) )
388 return anEngine._retn();
390 if ( SalomeApp_Application::moduleTitle( theComponentName ).isEmpty() )
391 return anEngine._retn();
393 std::string aPath( "/SalomeAppEngine/" );
394 aPath += theComponentName;
395 anEngine = namingService()->Resolve( aPath.c_str() );
397 // Activating a new instance of the servant
398 if ( toCreate && CORBA::is_nil( anEngine ) ){
400 SalomeApp_Engine_i* aServant = new SalomeApp_Engine_i( theComponentName );
401 PortableServer::ObjectId_var id = poa()->activate_object( aServant );
402 anEngine = aServant->_this();
403 aServant->_remove_ref();
404 namingService()->Register( anEngine.in(), aPath.c_str() );
406 catch (CORBA::SystemException&) {
407 INFOS("Caught CORBA::SystemException.");
409 catch (CORBA::Exception&) {
410 INFOS("Caught CORBA::Exception.");
413 INFOS("Caught unknown exception.");
417 return anEngine._retn();
421 \param theComponentName - synthetic "component data type" used to identify a given light module
422 \return IOR string for the CORBA engine for a light SALOME module
423 with the given "component data type" string
424 \sa GetInstance( const char* theComponentName )
426 std::string SalomeApp_Engine_i::EngineIORForComponent( const char* theComponentName,
429 std::string anIOR( "" );
430 CORBA::Object_var anEngine = EngineForComponent( theComponentName, toCreate );
431 if ( !CORBA::is_nil( anEngine ) )
433 CORBA::String_var objStr = orb()->object_to_string( anEngine.in() );
434 anIOR = std::string( objStr.in() );
440 \param theComponentName - synthetic "component data type" used to identify a given light module
441 \return A pointer to corresponding C++ engine instance, null means some internal problems.
442 \sa EngineIORForComponent( const char* theComponentName )
444 SalomeApp_Engine_i* SalomeApp_Engine_i::GetInstance( const char* theComponentName,
447 SalomeApp_Engine_i* aServant = 0;
448 CORBA::Object_var anEngine = EngineForComponent( theComponentName, toCreate );
449 if ( !CORBA::is_nil( anEngine ) )
451 PortableServer::Servant aServantBase = poa()->reference_to_servant( anEngine.in() );
452 aServant = dynamic_cast<SalomeApp_Engine_i*>( aServantBase );
454 MESSAGE("SalomeApp_Engine_i::GetInstance(): theComponentName = " <<
455 theComponentName << ", aServant = " << aServant);