From c68c4cb603eea86e135a60e3097f979e54c2aa42 Mon Sep 17 00:00:00 2001 From: san Date: Wed, 9 Nov 2011 16:27:58 +0000 Subject: [PATCH] [CEA 506] Connect light SALOME modules to "Dump Study" operation Issue #21377 (http://salome.mantis.opencascade.com/view.php?id=21377) --- src/LightApp/LightApp_DataModel.cxx | 9 + src/LightApp/LightApp_DataModel.h | 4 + .../SALOME_PYQT_DataModelLight.cxx | 31 ++ .../SALOME_PYQT_DataModelLight.h | 4 + .../SALOME_PYQT_ModuleLight.cxx | 70 ++++ .../SALOME_PYQT_ModuleLight.h | 7 +- src/SalomeApp/SalomeApp_Application.cxx | 31 +- src/SalomeApp/SalomeApp_Application.h | 1 - src/SalomeApp/SalomeApp_Study.cxx | 138 +++++++- src/SalomeApp/SalomeApp_Study.h | 2 + src/Session/SalomeApp_Engine_i.cxx | 306 +++++++++++++++--- src/Session/SalomeApp_Engine_i.hxx | 41 ++- src/Session/Session_ServerLauncher.cxx | 11 + src/Session/Session_ServerThread.cxx | 35 +- 14 files changed, 553 insertions(+), 137 deletions(-) diff --git a/src/LightApp/LightApp_DataModel.cxx b/src/LightApp/LightApp_DataModel.cxx index 0c8c40888..8c9675905 100644 --- a/src/LightApp/LightApp_DataModel.cxx +++ b/src/LightApp/LightApp_DataModel.cxx @@ -79,6 +79,15 @@ bool LightApp_DataModel::saveAs( const QString&, CAM_Study*, QStringList& ) return true; } +/*! + Does nothing by default. Should be redefined in light modules + that want to participate in "Dump study" operation. +*/ +bool LightApp_DataModel::dumpPython( const QString&, CAM_Study*, bool, QStringList& ) +{ + return true; +} + /*! Emit closed() */ diff --git a/src/LightApp/LightApp_DataModel.h b/src/LightApp/LightApp_DataModel.h index 994cbecaa..4da6d3675 100644 --- a/src/LightApp/LightApp_DataModel.h +++ b/src/LightApp/LightApp_DataModel.h @@ -55,6 +55,10 @@ public: virtual bool save( QStringList& ); virtual bool saveAs( const QString&, CAM_Study*, QStringList& ); virtual bool close(); + virtual bool dumpPython( const QString&, + CAM_Study*, + bool, + QStringList& ); virtual void update( LightApp_DataObject* = 0, LightApp_Study* = 0 ); diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx index 17c8f531b..2fc1d07c5 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.cxx @@ -115,6 +115,37 @@ bool SALOME_PYQT_DataModelLight::create( CAM_Study* study ) return true; } +//================================================================================= +// function : dumpPython() +// purpose : Re-defined from LigthApp_DataModel in order to participate +// in dump study process +//================================================================================= +bool SALOME_PYQT_DataModelLight::dumpPython( const QString& theURL, + CAM_Study* theStudy, + bool isMultiFile, + QStringList& theListOfFiles ) +{ + MESSAGE("SALOME_PYQT_DataModelLight::dumpPython()"); + + LightApp_DataModel::dumpPython( theURL, theStudy, isMultiFile, theListOfFiles ); + + LightApp_Study* study = dynamic_cast( theStudy ); + SALOME_PYQT_ModuleLight* aModule = dynamic_cast(module()); + + if(!aModule || !study) + return false; + + std::string aTmpDir = study->GetTmpDir( theURL.toLatin1().constData(), isMultiFile ); + + theListOfFiles.append( QString( aTmpDir.c_str() ) ); + int oldSize = theListOfFiles.size(); + + aModule->dumpPython( theListOfFiles ); + + //Return true if some items have been added, else return false + return theListOfFiles.size() > oldSize; +} + //================================================================================= // function : isModified() // purpose : default implementation, always returns false so as not to mask study's isModified() diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h index 2a6c2f21d..6f604cdc3 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_DataModelLight.h @@ -46,6 +46,10 @@ public: virtual bool saveAs ( const QString&, CAM_Study*, QStringList& ); virtual bool close (); virtual bool create ( CAM_Study* ); + virtual bool dumpPython( const QString&, + CAM_Study*, + bool, + QStringList& ); virtual bool isModified () const; virtual bool isSaved () const; diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx index a28601baf..825034ad7 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx @@ -2481,6 +2481,76 @@ void SALOME_PYQT_ModuleLight::saveEvent(QStringList& theListOfFiles) } } +/* + * Python dump request. + * Called when user activates dump study operation. + */ +void SALOME_PYQT_ModuleLight::dumpPython(QStringList& theListOfFiles) +{ + MESSAGE("SALOME_PYQT_ModuleLight::dumpPython()") + // perform synchronous request to Python event dispatcher + class DumpEvent: public PyInterp_LockRequest + { + public: + DumpEvent(PyInterp_Interp* _py_interp, + SALOME_PYQT_ModuleLight* _obj, + QStringList& _files_list) + : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) + myObj( _obj ) , + myFilesList(_files_list) {} + protected: + virtual void execute() + { + myObj->dumpEvent(myFilesList); + } + private: + SALOME_PYQT_ModuleLight* myObj; + QStringList& myFilesList; + }; + + // Posting the request only if dispatcher is not busy! + // Executing the request synchronously + if ( !PyInterp_Dispatcher::Get()->IsBusy() ) + PyInterp_Dispatcher::Get()->Exec( new DumpEvent( myInterp, this, theListOfFiles ) ); +} + +void SALOME_PYQT_ModuleLight::dumpEvent(QStringList& theListOfFiles) +{ + MESSAGE("SALOME_PYQT_ModuleLight::dumpEvent()"); + QStringList::Iterator it = theListOfFiles.begin(); + // Python interpreter should be initialized and Python module should be + // import first + if ( !myInterp || !myModule || (it == theListOfFiles.end())) + return; + + if ( PyObject_HasAttrString(myModule, (char*)"dumpStudy") ) { + PyObjWrapper res( PyObject_CallMethod( myModule, (char*)"dumpStudy", + (char*)"s", (*it).toLatin1().constData())); + if( !res ) { + PyErr_Print(); + } + else{ + // parse the return value + // result can be one string... + if ( PyString_Check( res ) ) { + QString astr = PyString_AsString( res ); + //SCRUTE(astr); + theListOfFiles.append(astr); + } + //also result can be a list... + else if ( PyList_Check( res ) ) { + int size = PyList_Size( res ); + for ( int i = 0; i < size; i++ ) { + PyObject* value = PyList_GetItem( res, i ); + if( value && PyString_Check( value ) ) { + theListOfFiles.append( PyString_AsString( value ) ); + } + } + } + } + } +} + /* * Open study request. * Called when user open study. diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h index 6917f3a1d..dbc6d21e8 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h @@ -123,9 +123,9 @@ public: void setPreferenceProperty( const int, const QString&, const QVariant& ); - void save(QStringList& theListOfFiles); - - bool open(QStringList theListOfFiles); + void save(QStringList& theListOfFiles); + bool open(QStringList theListOfFiles); + void dumpPython(QStringList& theListOfFiles); /*create new SALOME_PYQT_DataObjectLight and return its entry*/ QString createObject(const QString& parent); @@ -193,6 +193,7 @@ private: void connectView( const SUIT_ViewWindow* ); void saveEvent(QStringList& theListOfFiles); + void dumpEvent(QStringList& theListOfFiles); void openEvent(QStringList theListOfFiles, bool& opened); SALOME_PYQT_DataObjectLight* findObject(const QString& entry); diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index 97c8c1590..3ac65184b 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -812,21 +812,10 @@ void SalomeApp_Application::onDumpStudy( ) QFileInfo aFileInfo(aFileName); if( aFileInfo.isDir() ) // IPAL19257 return; + + // Issue 21377 - dump study implementation moved to SalomeApp_Study class + bool res = appStudy->dump( aFileName, toPublish, isMultiFile, toSaveGUI ); - int savePoint; - _PTR(AttributeParameter) ap; - _PTR(IParameters) ip = ClientFactory::getIParameters(ap); - if(ip->isDumpPython(appStudy->studyDS())) ip->setDumpPython(appStudy->studyDS()); //Unset DumpPython flag. - if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method - ip->setDumpPython(appStudy->studyDS()); - savePoint = SalomeApp_VisualState( this ).storeState(); //SRN: create a temporary save point - } - bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toStdString(), - aFileInfo.baseName().toStdString(), - toPublish, - isMultiFile); - if ( toSaveGUI ) - appStudy->removeSavePoint(savePoint); //SRN: remove the created temporary save point. if ( !res ) SUIT_MessageBox::warning( desktop(), QObject::tr("WRN_WARNING"), @@ -1222,20 +1211,6 @@ SALOME_LifeCycleCORBA* SalomeApp_Application::lcc() return &_lcc; } -/*!Return default engine IOR for light modules*/ -QString SalomeApp_Application::defaultEngineIOR() -{ - /// Look for a default module engine (needed for CORBAless modules to use SALOMEDS persistence) - QString anIOR( "" ); - CORBA::Object_ptr anEngine = namingService()->Resolve( "/SalomeAppEngine" ); - if ( !CORBA::is_nil( anEngine ) ) - { - CORBA::String_var objStr = orb()->object_to_string( anEngine ); - anIOR = QString( objStr.in() ); - } - return anIOR; -} - /*!Private SLOT. On preferences.*/ void SalomeApp_Application::onProperties() { diff --git a/src/SalomeApp/SalomeApp_Application.h b/src/SalomeApp/SalomeApp_Application.h index aab013d66..711333875 100644 --- a/src/SalomeApp/SalomeApp_Application.h +++ b/src/SalomeApp/SalomeApp_Application.h @@ -96,7 +96,6 @@ public: static SALOMEDSClient_StudyManager* studyMgr(); static SALOME_NamingService* namingService(); static SALOME_LifeCycleCORBA* lcc(); - static QString defaultEngineIOR(); SUIT_ViewManager* newViewManager(const QString&); void updateSavePointDataObjects( SalomeApp_Study* ); diff --git a/src/SalomeApp/SalomeApp_Study.cxx b/src/SalomeApp/SalomeApp_Study.cxx index 2972f8add..a7ffd3538 100644 --- a/src/SalomeApp/SalomeApp_Study.cxx +++ b/src/SalomeApp/SalomeApp_Study.cxx @@ -34,6 +34,7 @@ #include #include +#include #include "SALOME_Event.h" #include "Basics_Utils.hxx" @@ -503,7 +504,10 @@ bool SalomeApp_Study::saveDocumentAs( const QString& theFileName ) QListIterator it( list ); QStringList listOfFiles; while ( it.hasNext() ) { - if ( SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)it.next() ) { + // Cast to LightApp class in order to give a chance + // to light modules to save their data + if ( LightApp_DataModel* aModel = + dynamic_cast( it.next() ) ) { listOfFiles.clear(); aModel->saveAs( theFileName, this, listOfFiles ); if ( !listOfFiles.isEmpty() ) @@ -545,7 +549,10 @@ bool SalomeApp_Study::saveDocument() QListIterator it( list ); QStringList listOfFiles; while ( it.hasNext() ) { - if ( SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)it.next() ) { + // Cast to LightApp class in order to give a chance + // to light modules to save their data + if ( LightApp_DataModel* aModel = + dynamic_cast( it.next() ) ) { listOfFiles.clear(); aModel->save(listOfFiles); if ( !listOfFiles.isEmpty() ) @@ -590,6 +597,80 @@ void SalomeApp_Study::closeDocument(bool permanently) } } +/*! + Dump study operation. Writes a Python dump file using + SALOMEDS services. Additionally, gives a chance to light modules + to participate in dump study operation. + + \param theFileName - full path to the output Python file + \param toPublish - if true, all objects are published in a study + by the output script, including those not orignally present + in the current study. + \param isMultiFile - if true, each module's dump is written into + a separate Python file, otherwise a single output file is written + \param toSaveGUI - if true, the GUI state is written + + \return - true if the operation succeeds, and false otherwise. +*/ +bool SalomeApp_Study::dump( const QString& theFileName, + bool toPublish, + bool isMultiFile, + bool toSaveGUI ) +{ + int savePoint; + _PTR(AttributeParameter) ap; + _PTR(IParameters) ip = ClientFactory::getIParameters(ap); + _PTR(Study) aStudy = studyDS(); + + if( ip->isDumpPython( aStudy ) ) + ip->setDumpPython( aStudy ); //Unset DumpPython flag. + + if ( toSaveGUI ) { //SRN: Store a visual state of the study at the save point for DumpStudy method + ip->setDumpPython( aStudy ); + //SRN: create a temporary save point + savePoint = SalomeApp_VisualState( + dynamic_cast( application() ) ).storeState(); + } + + // Issue 21377 - Each data model is asked to dump its data not present in SALOMEDS study. + // This is an optional but important step, it gives a chance to light modules + // to dump their data as a part of common dump study operation + ModelList list; + dataModels( list ); + + QListIterator it( list ); + QStringList listOfFiles; + while ( it.hasNext() ) { + if ( LightApp_DataModel* aModel = + dynamic_cast( it.next() ) ) { + listOfFiles.clear(); + if ( aModel->dumpPython( theFileName, this, isMultiFile, listOfFiles ) && + !listOfFiles.isEmpty() ) + // This call simply passes the data model's dump output to SalomeApp_Engine servant. + // This code is shared with persistence mechanism. + // NOTE: this should be revised if behavior of saveModuleData() changes! + saveModuleData(aModel->module()->name(), listOfFiles); + } + } + + // Now dump SALOMEDS part that also involves SalomeApp_Engine in case if + // any light module is present in the current configuration + QFileInfo aFileInfo( theFileName ); + bool res = aStudy->DumpStudy( aFileInfo.absolutePath().toStdString(), + aFileInfo.baseName().toStdString(), + toPublish, + isMultiFile); + if ( toSaveGUI ) + removeSavePoint( savePoint ); //SRN: remove the created temporary save point. + + // Issue 21377 - Clean up light module data in SalomeApp_Engine servant + // This code is shared with persistence mechanism. + // NOTE: this should be revised if behavior of saveStudyData() changes! + saveStudyData( theFileName ); + + return res; +} + /*! \return true, if study is modified in comparison with last open/save */ @@ -667,16 +748,22 @@ void SalomeApp_Study::openModuleData( QString theModuleName, QStringList& theLis } /*! - Saves data from study + Re-implemented from LightApp_Study, actually does not save anything but + simply cleans up light modules' data */ bool SalomeApp_Study::saveStudyData( const QString& theFileName ) { ModelList list; dataModels( list ); QListIterator it( list ); std::vector listOfFiles(0); - while ( it.hasNext() ) - if ( SalomeApp_DataModel* aModel = (SalomeApp_DataModel*)it.next() ) - SetListOfFiles(aModel->module()->name().toStdString().c_str(), listOfFiles); + while ( it.hasNext() ){ + LightApp_DataModel* aLModel = + dynamic_cast( it.next() ); + // It is safe to call SetListOfFiles() for any kind of module + // because SetListOfFiles() does nothing for full modules :) + if ( aLModel ) + SetListOfFiles(aLModel->module()->name().toStdString().c_str(), listOfFiles); + } return true; } @@ -735,7 +822,7 @@ CAM_ModuleObject* SalomeApp_Study::createModuleObject( LightApp_DataModel* theDa _PTR(SComponent) aComp = aStudy->FindComponent( theDataModel->module()->name().toStdString() ); - if ( aComp ) + if ( !aComp ) return res; res = new SalomeApp_ModuleObject( theDataModel, aComp, theParent ); @@ -768,11 +855,14 @@ void SalomeApp_Study::addComponent(const CAM_DataModel* dm) _PTR(Study) aStudy = studyDS(); if (!aStudy) return; - _PTR(SComponent) aComp = aStudy->FindComponent(dm->module()->name().toStdString()); + + std::string aCompDataType = dm->module()->name().toStdString(); + + _PTR(SComponent) aComp = aStudy->FindComponent(aCompDataType); if (!aComp) { // Create SComponent _PTR(StudyBuilder) aBuilder = aStudy->NewBuilder(); - aComp = aBuilder->NewComponent(dm->module()->name().toStdString()); + aComp = aBuilder->NewComponent(aCompDataType); aBuilder->SetName(aComp, dm->module()->moduleName().toStdString()); QString anIconName = dm->module()->iconName(); if (!anIconName.isEmpty()) { @@ -780,8 +870,12 @@ void SalomeApp_Study::addComponent(const CAM_DataModel* dm) if (anAttr) anAttr->SetPixMap(anIconName.toStdString()); } + // Set default engine IOR - aBuilder->DefineComponentInstance(aComp, SalomeApp_Application::defaultEngineIOR().toStdString()); + // Issue 21377 - using separate engine for each type of light module + std::string anEngineIOR = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), + true ); + aBuilder->DefineComponentInstance(aComp, anEngineIOR); //SalomeApp_DataModel::BuildTree( aComp, root(), this, /*skipExisitng=*/true ); SalomeApp_DataModel::synchronize( aComp, this ); } @@ -803,8 +897,10 @@ bool SalomeApp_Study::openDataModel( const QString& studyName, CAM_DataModel* dm QString anEngine; // 1. aModule == 0 means that this is a light module (no CORBA enigine) if (!aModule) { - anEngine = SalomeApp_Application::defaultEngineIOR(); - aSComp = aStudy->FindComponent(dm->module()->name().toStdString()); + // Issue 21377 - using separate engine for each type of light module + std::string aCompDataType = dm->module()->name().toStdString(); + anEngine = SalomeApp_Engine_i::EngineIORForComponent( aCompDataType.c_str(), true ).c_str(); + aSComp = aStudy->FindComponent( aCompDataType ); } else { SalomeApp_DataModel* aDM = dynamic_cast( dm ); @@ -876,30 +972,38 @@ QString SalomeApp_Study::newStudyName() const } /*! + Note that this method does not create or activate SalomeApp_Engine_i instance, + therefore it can be called safely for any kind of module, but for full + modules it returns an empty list. \return list of files used by module: to be used by CORBAless modules \param theModuleName - name of module */ std::vector SalomeApp_Study::GetListOfFiles( const char* theModuleName ) const { - SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance(); + // Issue 21377 - using separate engine for each type of light module + SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false ); if (aDefaultEngine) - return aDefaultEngine->GetListOfFiles(id(), theModuleName); + return aDefaultEngine->GetListOfFiles(id()); std::vector aListOfFiles; return aListOfFiles; } /*! - Sets list of files used by module: to be used by CORBAless modules + Sets list of files used by module: to be used by CORBAless modules. + Note that this method does not create or activate SalomeApp_Engine_i instance, + therefore it can be called safely for any kind of module, but for full + modules it simply does nothing. \param theModuleName - name of module \param theListOfFiles - list of files */ void SalomeApp_Study::SetListOfFiles ( const char* theModuleName, const std::vector theListOfFiles ) { - SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance(); + // Issue 21377 - using separate engine for each type of light module + SalomeApp_Engine_i* aDefaultEngine = SalomeApp_Engine_i::GetInstance( theModuleName, false ); if (aDefaultEngine) - aDefaultEngine->SetListOfFiles(theListOfFiles, id(), theModuleName); + aDefaultEngine->SetListOfFiles(theListOfFiles, id()); } /*! diff --git a/src/SalomeApp/SalomeApp_Study.h b/src/SalomeApp/SalomeApp_Study.h index 41ebe3715..2487cd5de 100644 --- a/src/SalomeApp/SalomeApp_Study.h +++ b/src/SalomeApp/SalomeApp_Study.h @@ -55,6 +55,8 @@ public: virtual void closeDocument(bool permanently = true); + virtual bool dump( const QString&, bool, bool, bool ); + virtual bool isSaved() const; virtual bool isModified() const; virtual void Modified(); diff --git a/src/Session/SalomeApp_Engine_i.cxx b/src/Session/SalomeApp_Engine_i.cxx index 639d3e84f..c31e83fb3 100644 --- a/src/Session/SalomeApp_Engine_i.cxx +++ b/src/Session/SalomeApp_Engine_i.cxx @@ -28,20 +28,29 @@ // #include "SalomeApp_Engine_i.hxx" -#include "SALOMEDS_Tool.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include using namespace std; -SalomeApp_Engine_i* SalomeApp_Engine_i::myInstance = NULL; - /*! Constructor */ -SalomeApp_Engine_i::SalomeApp_Engine_i() +SalomeApp_Engine_i::SalomeApp_Engine_i( const char* theComponentName ) { - myInstance = this; + myComponentName = theComponentName; + MESSAGE("SalomeApp_Engine_i::SalomeApp_Engine_i(): myComponentName = "<< + myComponentName << ", this = " << this); } /*! @@ -49,6 +58,8 @@ SalomeApp_Engine_i::SalomeApp_Engine_i() */ SalomeApp_Engine_i::~SalomeApp_Engine_i() { + MESSAGE("SalomeApp_Engine_i::~SalomeApp_Engine_i(): myComponentName = " << myComponentName << + myComponentName << ", this = " << this); } SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theComponent, @@ -57,22 +68,23 @@ SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theCompone { SALOMEDS::TMPFile_var aStreamFile = new SALOMEDS::TMPFile; - cout << "SalomeApp_Engine_i::Save() isMultiFile = " << isMultiFile << endl; if (CORBA::is_nil(theComponent) || CORBA::is_nil(theComponent->GetStudy())) return aStreamFile._retn(); const int studyId = theComponent->GetStudy()->StudyId(); - cout << "SalomeApp_Engine_i::Save() - studyId = " << studyId << endl; // Get a temporary directory to store a file //std::string aTmpDir = isMultiFile ? theURL : SALOMEDS_Tool::GetTmpDir(); if (myMap.count(studyId)) { - cout << "SalomeApp_Engine_i::Save() - myMap.count(studyId)" << endl; - MapOfListOfFiles mapOfListOfFiles = myMap[studyId]; std::string componentName (theComponent->ComponentDataType()); - cout << "SalomeApp_Engine_i::Save() - componentName = " << componentName << endl; - ListOfFiles listOfFiles = mapOfListOfFiles[componentName]; + + // Error somewhere outside - Save() called with + // wrong SComponent instance + if ( myComponentName != componentName ) + return aStreamFile._retn(); + + const ListOfFiles& listOfFiles = myMap[studyId]; // listOfFiles must contain temporary directory name in its first item // and names of files (relatively the temporary directory) in the others @@ -80,7 +92,6 @@ SALOMEDS::TMPFile* SalomeApp_Engine_i::Save (SALOMEDS::SComponent_ptr theCompone if (n > 0) { // there are some files, containing persistent data of the component std::string aTmpDir = listOfFiles[0]; - cout << "SalomeApp_Engine_i::Save() - aTmpDir = " << aTmpDir << endl; // Create a list to store names of created files SALOMEDS::ListOfFileNames_var aSeq = new SALOMEDS::ListOfFileNames; @@ -108,6 +119,12 @@ CORBA::Boolean SalomeApp_Engine_i::Load (SALOMEDS::SComponent_ptr theComponent, if (CORBA::is_nil(theComponent) || CORBA::is_nil(theComponent->GetStudy())) return false; + // Error somewhere outside - Load() called with + // wrong SComponent instance + std::string componentName (theComponent->ComponentDataType()); + if ( myComponentName != componentName ) + return false; + const int studyId = theComponent->GetStudy()->StudyId(); // Create a temporary directory for the component's data files @@ -125,52 +142,259 @@ CORBA::Boolean SalomeApp_Engine_i::Load (SALOMEDS::SComponent_ptr theComponent, for (int i = 1; i < n; i++) listOfFiles[i] = std::string(aSeq[i - 1]); - //MapOfListOfFiles mapOfListOfFiles; - //if (myMap.count(studyId)) - // mapOfListOfFiles = myMap[studyId]; - //std::string componentName (theComponent->ComponentDataType()); - //mapOfListOfFiles[componentName] = listOfFiles; - //myMap[studyId] = mapOfListOfFiles; - - SetListOfFiles(listOfFiles, studyId, theComponent->ComponentDataType()); + SetListOfFiles(listOfFiles, studyId); return true; } -SalomeApp_Engine_i::ListOfFiles SalomeApp_Engine_i::GetListOfFiles (const int theStudyId, - const char* theComponentName) +SalomeApp_Engine_i::ListOfFiles SalomeApp_Engine_i::GetListOfFiles (const int theStudyId) { ListOfFiles aListOfFiles; - if (myMap.count(theStudyId)) + if (myMap.find(theStudyId) != myMap.end()) { - MapOfListOfFiles mapOfListOfFiles = myMap[theStudyId]; - std::string componentName (theComponentName); - if (mapOfListOfFiles.count(componentName)) - aListOfFiles = mapOfListOfFiles[componentName]; + aListOfFiles = myMap[theStudyId]; } return aListOfFiles; } -void SalomeApp_Engine_i::SetListOfFiles (const ListOfFiles theListOfFiles, - const int theStudyId, - const char* theComponentName) +void SalomeApp_Engine_i::SetListOfFiles (const ListOfFiles& theListOfFiles, + const int theStudyId) { - //if (!myMap.count(theStudyId)) { - // MapOfListOfFiles mapOfListOfFiles; - // myMap[theStudyId] = mapOfListOfFiles; - //} - - MapOfListOfFiles& mapOfListOfFiles = myMap[theStudyId]; - std::string componentName (theComponentName); - mapOfListOfFiles[componentName] = theListOfFiles; + myMap[theStudyId] = theListOfFiles; +} + +/*! + * DumpPython implementation for light modules + */ +Engines::TMPFile* SalomeApp_Engine_i::DumpPython(CORBA::Object_ptr theStudy, + CORBA::Boolean isPublished, + CORBA::Boolean isMultiFile, + CORBA::Boolean& isValidScript) +{ + MESSAGE("SalomeApp_Engine_i::DumpPython(): myComponentName = "<< + myComponentName << ", this = " << this); + + // Temporary solution: returning a non-empty sequence + // even if there's nothing to dump, to avoid crashes in SALOMEDS + // TODO: Improve SALOMEDSImpl_Study::DumpStudy() by skipping the components + // with isValidScript == false, and initialize isValidScript by false below. + Engines::TMPFile_var aStreamFile = new Engines::TMPFile(1); + aStreamFile->length( 1 ); + aStreamFile[0] = '\0'; + isValidScript = true; + + if (CORBA::is_nil(theStudy)) + return aStreamFile._retn(); + + SALOMEDS::Study_var studyDS = SALOMEDS::Study::_narrow( theStudy ); + const int studyId = studyDS->StudyId(); + + if (!myMap.count(studyId)) + return aStreamFile._retn(); + + ListOfFiles listOfFiles = myMap[studyId]; + + // listOfFiles must contain temporary directory name in its first item + // and names of files (relatively the temporary directory) in the others + if ( listOfFiles.size() < 2 ) + return aStreamFile._retn(); + + // there are some files, containing persistent data of the component + QString aTmpPath( listOfFiles.front().c_str() ); + QDir aTmpDir( aTmpPath ); + if ( !aTmpDir.exists() ) + return aStreamFile._retn(); + + // Calculate file sizes + QStringList aFilePaths; + QList aFileSizes; + qint64 aBuffSize = 0; + ListOfFiles::const_iterator aFIt = listOfFiles.begin(); + ListOfFiles::const_iterator aFEnd = listOfFiles.end(); + aFIt++; + for (; aFIt != aFEnd; aFIt++){ + QString aFileName( (*aFIt).c_str() ); + if ( !aTmpDir.exists( aFileName ) ){ + continue; + } + + QFile aFile( aTmpDir.filePath( aFileName ) ); + if ( !aFile.open( QIODevice::ReadOnly ) ){ + continue; + } + + aFilePaths.push_back( aTmpDir.filePath( aFileName ) ); + aFileSizes.push_back( aFile.size() ); + aBuffSize += aFileSizes.back(); + + aFile.close(); + } + + if ( !aFilePaths.size() || !aBuffSize ) + return aStreamFile._retn(); + + char* aBuffer = new char[aBuffSize + 1]; + if ( !aBuffer ) + return aStreamFile._retn(); + + // Convert the file(s) to the byte stream, multiple files are simply + // concatenated + // TODO: imporve multi-script support if necessary... + qint64 aCurrPos = 0; + QStringList::const_iterator aFileIt = aFilePaths.begin(); + QStringList::const_iterator aFileEnd = aFilePaths.end(); + QList::const_iterator aSIt = aFileSizes.begin(); + for ( ; aFileIt != aFileEnd; aFileIt++, aSIt++ ){ + QFile aFile( aTmpDir.filePath( *aFileIt ) ); + if ( !aFile.open( QIODevice::ReadOnly ) ){ + continue; + } + + // Incorrect size of file + // Do not remove the bad file to have some diagnostic means + if ( aFile.read( aBuffer + aCurrPos, *aSIt ) != *aSIt ){ + aFile.close(); + return aStreamFile._retn(); + } + + aCurrPos += (*aSIt); + aFile.remove(); + } + + // Here we should end up with empty aTmpDir + // TODO: Handle QDir::rmdir() error status somehow... + aTmpDir.rmdir( aTmpPath ); + + aBuffer[aBuffSize] = '\0'; + CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer; + aStreamFile = new Engines::TMPFile(aBuffSize + 1, aBuffSize + 1, anOctetBuf, 1); + + return aStreamFile._retn(); } /*! - \return shared instance of engine + \return Component data type string for this instance of the engine */ -SalomeApp_Engine_i* SalomeApp_Engine_i::GetInstance() +char* SalomeApp_Engine_i::ComponentDataType() { - return myInstance; + return const_cast( myComponentName.c_str() ); } + +/*! + \return +*/ +CORBA::ORB_var SalomeApp_Engine_i::orb() +{ + ORB_INIT& init = *SINGLETON_::Instance(); + // TODO: using QApplication here looks ugly, think how to + // obtain the ORB reference in a nicer way... + static CORBA::ORB_var _orb = init( qApp->argc(), qApp->argv() ); + return _orb; +} + +/*! + \return +*/ +PortableServer::POA_var SalomeApp_Engine_i::poa() +{ + static PortableServer::POA_var _poa; + if ( CORBA::is_nil( _poa ) ){ + CORBA::Object_var obj = orb()->resolve_initial_references( "RootPOA" ); + _poa = PortableServer::POA::_narrow( obj ); + } + return _poa; +} + +/*! + \return +*/ +SALOME_NamingService* SalomeApp_Engine_i::namingService() +{ + static SALOME_NamingService _ns(orb()); + return &_ns; +} + +/*! + Internal method, creates a CORBA engine for a light SALOME module + with the given "component data type" string, + activates it and registers in SALOME naming service with + /SalomeAppEngine/comp_data_type path. If the engine is already in the + naming service, simply returns and object reference to it. + \param theComponentName - synthetic "component data type" used to identify a given light module + \return Object reference to the CORBA engine +*/ +CORBA::Object_ptr SalomeApp_Engine_i::engineForComponent( const char* theComponentName, + bool toCreate ) +{ + CORBA::Object_var anEngine; + if ( !theComponentName || !strlen( theComponentName ) ) + return anEngine._retn(); + + std::string aPath( "/SalomeAppEngine/" ); + aPath += theComponentName; + anEngine = namingService()->Resolve( aPath.c_str() ); + + // Activating a new instance of the servant + if ( toCreate && CORBA::is_nil( anEngine ) ){ + try { + SalomeApp_Engine_i* aServant = new SalomeApp_Engine_i( theComponentName ); + PortableServer::ObjectId_var id = poa()->activate_object( aServant ); + anEngine = aServant->_this(); + aServant->_remove_ref(); + namingService()->Register( anEngine.in(), aPath.c_str() ); + } + catch (CORBA::SystemException&) { + INFOS("Caught CORBA::SystemException."); + } + catch (CORBA::Exception&) { + INFOS("Caught CORBA::Exception."); + } + catch (...) { + INFOS("Caught unknown exception."); + } + } + + return anEngine._retn(); +} + +/*! + \param theComponentName - synthetic "component data type" used to identify a given light module + \return IOR string for the CORBA engine for a light SALOME module + with the given "component data type" string + \sa GetInstance( const char* theComponentName ) +*/ +std::string SalomeApp_Engine_i::EngineIORForComponent( const char* theComponentName, + bool toCreate ) +{ + std::string anIOR( "" ); + CORBA::Object_var anEngine = engineForComponent( theComponentName, toCreate ); + if ( !CORBA::is_nil( anEngine ) ) + { + CORBA::String_var objStr = orb()->object_to_string( anEngine.in() ); + anIOR = std::string( objStr.in() ); + } + return anIOR; +} + +/*! + \param theComponentName - synthetic "component data type" used to identify a given light module + \return A pointer to corresponding C++ engine instance, null means some internal problems. + \sa EngineIORForComponent( const char* theComponentName ) +*/ +SalomeApp_Engine_i* SalomeApp_Engine_i::GetInstance( const char* theComponentName, + bool toCreate ) +{ + SalomeApp_Engine_i* aServant = 0; + CORBA::Object_var anEngine = engineForComponent( theComponentName, toCreate ); + if ( !CORBA::is_nil( anEngine ) ) + { + PortableServer::Servant aServantBase = poa()->reference_to_servant( anEngine.in() ); + aServant = dynamic_cast( aServantBase ); + } + MESSAGE("SalomeApp_Engine_i::GetInstance(): theComponentName = " << + theComponentName << ", aServant = " << aServant); + return aServant; +} + diff --git a/src/Session/SalomeApp_Engine_i.hxx b/src/Session/SalomeApp_Engine_i.hxx index 965f46b9c..e9030cbb7 100755 --- a/src/Session/SalomeApp_Engine_i.hxx +++ b/src/Session/SalomeApp_Engine_i.hxx @@ -39,11 +39,13 @@ #include #include CORBA_SERVER_HEADER(SalomeApp_Engine) +class SALOME_NamingService; + class SESSION_EXPORT SalomeApp_Engine_i: public POA_SalomeApp::Engine, - public Engines_Component_i + public Engines_Component_i { public: - SalomeApp_Engine_i(); + SalomeApp_Engine_i( const char* theComponentName ); ~SalomeApp_Engine_i(); SALOMEDS::TMPFile* Save( SALOMEDS::SComponent_ptr theComponent, @@ -55,17 +57,22 @@ public: const char* theURL, bool isMultiFile ); + virtual Engines::TMPFile* DumpPython(CORBA::Object_ptr theStudy, + CORBA::Boolean isPublished, + CORBA::Boolean isMultiFile, + CORBA::Boolean& isValidScript); + public: typedef std::vector ListOfFiles; - ListOfFiles GetListOfFiles (const int theStudyId, - const char* theComponentName); - - void SetListOfFiles (const ListOfFiles theListOfFiles, - const int theStudyId, - const char* theComponentName); + ListOfFiles GetListOfFiles (const int theStudyId); + void SetListOfFiles (const ListOfFiles& theListOfFiles, + const int theStudyId); - static SalomeApp_Engine_i* GetInstance(); + static std::string EngineIORForComponent( const char* theComponentName, + bool toCreate ); + static SalomeApp_Engine_i* GetInstance ( const char* theComponentName, + bool toCreate ); public: // methods from SALOMEDS::Driver without implementation. Must be redefined because @@ -73,7 +80,7 @@ public: SALOMEDS::TMPFile* SaveASCII( SALOMEDS::SComponent_ptr, const char*, bool ) {return 0;} CORBA::Boolean LoadASCII( SALOMEDS::SComponent_ptr, const SALOMEDS::TMPFile&, const char*, bool ) {return 0;} void Close( SALOMEDS::SComponent_ptr ) {} - char* ComponentDataType() {return 0;} + char* ComponentDataType(); char* IORToLocalPersistentID( SALOMEDS::SObject_ptr, const char*, CORBA::Boolean, CORBA::Boolean ) {return 0;} char* LocalPersistentIDToIOR( SALOMEDS::SObject_ptr, const char*, CORBA::Boolean, CORBA::Boolean ) {return 0;} bool CanPublishInStudy( CORBA::Object_ptr ) {return 0;} @@ -84,11 +91,17 @@ public: SALOMEDS::SObject_ptr PasteInto( const SALOMEDS::TMPFile&, CORBA::Long, SALOMEDS::SObject_ptr ) {return 0;} private: - typedef std::map MapOfListOfFiles; - typedef std::map MapOfMapOfListOfFiles; - MapOfMapOfListOfFiles myMap; + static CORBA::ORB_var orb(); + static PortableServer::POA_var poa(); + static SALOME_NamingService* namingService(); + static CORBA::Object_ptr engineForComponent( const char* theComponentName, + bool toCreate ); + +private: + typedef std::map MapOfListOfFiles; + MapOfListOfFiles myMap; - static SalomeApp_Engine_i* myInstance; + std::string myComponentName; }; #endif diff --git a/src/Session/Session_ServerLauncher.cxx b/src/Session/Session_ServerLauncher.cxx index df8422f8f..71a8503aa 100755 --- a/src/Session/Session_ServerLauncher.cxx +++ b/src/Session/Session_ServerLauncher.cxx @@ -127,6 +127,17 @@ void Session_ServerLauncher::CheckArgs() } case 1: // looking for server type { + // Temporary solution + // Issue 21337 - no more SalomeApp_Engine_i activation here + // TODO: To be removed as soon as any trace of SalomeAppEngine + // has been eliminated from KERNEL scripts + if (strcmp(_argv[iarg], "SalomeAppEngine")==0){ + argState = 0; + iarg += 2; // skipping "()" + break; + } + // Temporary solution + for (int i=0; i #include "Session_Session_i.hxx" -#include "SalomeApp_Engine_i.hxx" #include #include @@ -56,13 +55,12 @@ using namespace std; -const int Session_ServerThread::NB_SRV_TYP = 7; +const int Session_ServerThread::NB_SRV_TYP = 6; const char* Session_ServerThread::_serverTypes[NB_SRV_TYP] = {"Container", "ModuleCatalog", "Registry", "SALOMEDS", "Session", - "SalomeAppEngine", "ContainerManager"}; /*! @@ -158,13 +156,7 @@ void Session_ServerThread::Init() ActivateSession(_argc, _argv); break; } - case 5: // SalomeApp_Engine - { - NamingService_WaitForServerReadiness(_NS,"/myStudyManager"); - ActivateEngine(_argc, _argv); - break; - } - case 6: // Container Manager + case 5: // Container Manager { NamingService_WaitForServerReadiness(_NS,""); ActivateContainerManager(_argc, _argv); @@ -390,29 +382,6 @@ void Session_ServerThread::ActivateContainer(int argc, } } -void Session_ServerThread::ActivateEngine(int /*argc*/, char ** /*argv*/) -{ - try { - MESSAGE("SalomeApp_Engine thread started"); - SalomeApp_Engine_i* anEngine = new SalomeApp_Engine_i(); - PortableServer::ObjectId_var id =_root_poa->activate_object( anEngine ); - MESSAGE("poa->activate_object( SalomeApp_Engine )"); - - CORBA::Object_var obj = anEngine->_this(); - anEngine->_remove_ref(); - _NS->Register( obj ,"/SalomeAppEngine"); - } - catch (CORBA::SystemException&) { - INFOS("Caught CORBA::SystemException."); - } - catch (CORBA::Exception&) { - INFOS("Caught CORBA::Exception."); - } - catch (...) { - INFOS("Caught unknown exception."); - } -} - void Session_ServerThread::ActivateSession(int argc, char ** argv) { -- 2.39.2