Salome HOME
[EDF17719] : Comparison between 2 objects is now a user defined function called ...
[modules/kernel.git] / src / SALOMESDS / SALOMESDS_DataScopeServer.cxx
index 76a78c8ee724e66b2a0b309f5001459a74306260..d8b70ef3a8f620bfddf96e5da172a5b57236d654 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -46,12 +46,44 @@ using namespace SALOMESDS;
 
 std::size_t DataScopeServerBase::COUNTER=0;
 
+#if PY_VERSION_HEX < 0x03050000
+static char*
+Py_EncodeLocale(const wchar_t *arg, size_t *size)
+{
+       return _Py_wchar2char(arg, size);
+}
+static wchar_t*
+Py_DecodeLocale(const char *arg, size_t *size)
+{
+       return _Py_char2wchar(arg, size);
+}
+#endif
+
 void DataScopeKiller::shutdown()
 {
   Py_Finalize();
   _orb->shutdown(0);
 }
 
+RequestSwitcher::RequestSwitcher(CORBA::ORB_ptr orb, DataScopeServerTransaction *ds):RequestSwitcherBase(orb),_ds(ds)
+{
+}
+
+SALOME::StringVec *RequestSwitcher::listVars()
+{
+  return _ds->listVars();
+}
+
+SALOME::ByteVec *RequestSwitcher::fetchSerializedContent(const char *varName)
+{
+  return _ds->fetchSerializedContent(varName);
+}
+
+void RequestSwitcher::fetchAndGetAccessOfVar(const char *varName, CORBA::String_out access, SALOME::ByteVec_out data)
+{
+  return _ds->fetchAndGetAccessOfVar(varName,access,data);
+}
+
 DataScopeServerBase::DataScopeServerBase(CORBA::ORB_ptr orb, SALOME::DataScopeKiller_var killer, const std::string& scopeName):_globals(0),_locals(0),_pickler(0),_orb(CORBA::ORB::_duplicate(orb)),_name(scopeName),_killer(killer)
 {
 }
@@ -226,11 +258,32 @@ SALOME::SeqOfByteVec *DataScopeServerBase::getAllKeysOfVarWithTypeDict(const cha
   return ret;
 }
 
+void DataScopeServerBase::takeANap(CORBA::Double napDurationInSec)
+{
+  if(napDurationInSec<0.)
+    throw Exception("DataScopeServerBase::takeANap : negative value !");
+#ifndef WIN32
+  struct timespec req,rem;
+  long nbSec((long)napDurationInSec);
+  double remainTime(napDurationInSec-(double)nbSec);
+  req.tv_sec=nbSec;
+  req.tv_nsec=(long)(remainTime*1000000.);
+  int ret(nanosleep(&req,&rem));
+  if(ret!=0)
+    throw Exception("DataScopeServerBase::takeANap : nap not finished as expected !");
+#else
+  throw Exception("DataScopeServerBase::takeANap : not implemented for Windows !");
+#endif
+}
+
 void DataScopeServerBase::initializePython(int argc, char *argv[])
 {
   Py_Initialize();
   PyEval_InitThreads();
-  PySys_SetArgv(argc,argv);
+  wchar_t **changed_argv = new wchar_t*[argc]; // Setting arguments
+  for (int i = 0; i < argc; i++)
+    changed_argv[i] = Py_DecodeLocale(argv[i], NULL);
+  PySys_SetArgv(argc, changed_argv);
   PyObject *mainmod(PyImport_AddModule("__main__"));
   _globals=PyModule_GetDict(mainmod);
   if(PyDict_GetItemString(_globals, "__builtins__") == NULL)
@@ -242,7 +295,7 @@ void DataScopeServerBase::initializePython(int argc, char *argv[])
     }
   _locals=PyDict_New();
   PyObject *tmp(PyList_New(0));
-  _pickler=PyImport_ImportModuleLevel(const_cast<char *>("cPickle"),_globals,_locals,tmp,-1);
+  _pickler=PyImport_ImportModuleLevel(const_cast<char *>("pickle"),_globals,_locals,tmp,0);
 }
 
 void DataScopeServerBase::registerToSalomePiDict() const
@@ -254,8 +307,8 @@ void DataScopeServerBase::registerToSalomePiDict() const
   if(!meth)
     { Py_XDECREF(mod); return ; }
   PyObject *args(PyTuple_New(2));
-  PyTuple_SetItem(args,0,PyInt_FromLong(getpid()));
-  PyTuple_SetItem(args,1,PyString_FromString("SALOME_DataScopeServerBase"));
+  PyTuple_SetItem(args,0,PyLong_FromLong(getpid()));
+  PyTuple_SetItem(args,1,PyUnicode_FromString("SALOME_DataScopeServerBase"));
   PyObject *res(PyObject_CallObject(meth,args));
   Py_XDECREF(args);
   Py_XDECREF(res);
@@ -292,11 +345,16 @@ std::vector< std::string > DataScopeServerBase::getAllVarNames() const
   return ret;
 }
 
-void DataScopeServerBase::checkNotAlreadyExistingVar(const std::string& varName) const
+bool DataScopeServerBase::isExistingVar(const std::string& varName) const
 {
   std::vector<std::string> allNames(getAllVarNames());
   std::vector<std::string>::iterator it(std::find(allNames.begin(),allNames.end(),varName));
-  if(it!=allNames.end())
+  return it!=allNames.end();
+}
+
+void DataScopeServerBase::checkNotAlreadyExistingVar(const std::string& varName) const
+{
+  if(isExistingVar(varName))
     {
       std::ostringstream oss; oss << "DataScopeServerBase::checkNotAlreadyExistingVar : name \"" << varName << "\" already exists !";
       throw Exception(oss.str());
@@ -372,31 +430,35 @@ void DataScopeServerBase::moveStatusOfVarFromRdExtOrRdExtInitToRdExtInit(const s
     throw Exception("DataScopeServerBase::moveStatusOfVarFromRdExtOrRdExtInitToRdExtInit : var is neither RdExt nor RdExtInit !");
   if(varc0)
     {
-      PyObject *pyobj(varc0->getPyObj()); Py_XINCREF(pyobj);
-      PickelizedPyObjRdExtInitServer *newVar(new PickelizedPyObjRdExtInitServer(this,varName,pyobj));
+      PickelizedPyObjRdExtInitServer *newVar(varc0->buildInitInstanceFrom(varName));
+      newVar->incrNbClients();
       CORBA::Object_var obj(newVar->activate());
       SALOME::BasicDataServer_var obj2(SALOME::BasicDataServer::_narrow(obj));
       p.first=obj2; p.second=newVar;
       varc0->decrRef();
     }
+  else
+    varc1->incrNbClients();
 }
 
-void DataScopeServerBase::moveStatusOfVarFromRdExtInitToRdExt(const std::string& varName)
+void DataScopeServerBase::moveStatusOfVarFromRdExtOrRdExtInitToRdExt(const std::string& varName)
 {
   std::list< std::pair< SALOME::BasicDataServer_var, BasicDataServer * > >::iterator it(retrieveVarInternal4(varName));
   std::pair< SALOME::BasicDataServer_var, BasicDataServer * >& p(*it);
   PickelizedPyObjRdExtInitServer *varc0(dynamic_cast<PickelizedPyObjRdExtInitServer *>(p.second));
   PickelizedPyObjRdExtServer *varc1(dynamic_cast<PickelizedPyObjRdExtServer *>(p.second));
   if(!varc0 && !varc1)
-    throw Exception("DataScopeServerBase::moveStatusOfVarFromRdExtInitToRdExt : var is not a RdExtInit !");
+    throw Exception("DataScopeServerBase::moveStatusOfVarFromRdExtOrRdExtInitToRdExt : var is not a RdExtInit !");
   if(varc0)
     {
-      PyObject *pyobj(varc0->getPyObj()); Py_XINCREF(pyobj);
-      PickelizedPyObjRdExtServer *newVar(new PickelizedPyObjRdExtServer(this,varName,pyobj));
-      CORBA::Object_var obj(newVar->activate());
-      SALOME::BasicDataServer_var obj2(SALOME::BasicDataServer::_narrow(obj));
-      p.first=obj2; p.second=newVar;
-      varc0->decrRef();
+      if(varc0->decrNbClients())
+        {
+          PickelizedPyObjRdExtServer *newVar(varc0->buildStdInstanceFrom(varName));
+          CORBA::Object_var obj(newVar->activate());
+          SALOME::BasicDataServer_var obj2(SALOME::BasicDataServer::_narrow(obj));
+          p.first=obj2; p.second=newVar;
+          varc0->decrRef();
+        }
     }
 }
 
@@ -515,6 +577,15 @@ char *DataScopeServerTransaction::getAccessOfVar(const char *varName)
   return CORBA::string_dup(ret.c_str());
 }
 
+/*!
+ * This method is here to retrieve atomically accessStr and picklization.
+ */
+void DataScopeServerTransaction::fetchAndGetAccessOfVar(const char *varName, CORBA::String_out access, SALOME::ByteVec_out data)
+{
+  access=getAccessOfVar(varName);
+  data=fetchSerializedContent(varName);
+}
+
 void DataScopeServerTransaction::createRdOnlyVarInternal(const std::string& varName, const SALOME::ByteVec& constValue)
 {
   checkNotAlreadyExistingVar(varName);
@@ -533,6 +604,51 @@ void DataScopeServerTransaction::createRdExtVarInternal(const std::string& varNa
   _vars.push_back(p);
 }
 
+void DataScopeServerTransaction::createRdExtVarFreeStyleInternal(const std::string& varName, const SALOME::ByteVec& constValue, std::string&& compareFuncContent, SALOME::AutoPyRef&& compareFunc)
+{
+  if(!isExistingVar(varName))
+    {
+      PickelizedPyObjRdExtFreeStyleServer *tmp(new PickelizedPyObjRdExtFreeStyleServer(this,varName,constValue,std::move(compareFuncContent),std::move(compareFunc)));
+      CORBA::Object_var ret(tmp->activate());
+      std::pair< SALOME::BasicDataServer_var, BasicDataServer * > p(SALOME::BasicDataServer::_narrow(ret),tmp);
+      _vars.push_back(p);
+    }
+  else
+    {
+      BasicDataServer *ds(retrieveVarInternal2(varName));
+      if(!ds)
+        {
+          std::ostringstream oss;
+          oss << "DataScopeServerTransaction::createRdExtVarFreeStyleInternal : internal error 1 for varname \"" << varName << "\"!";
+          throw Exception(oss.str());
+        }
+      Sha1Keeper *ds2(dynamic_cast<Sha1Keeper *>(ds));
+      if(!ds2)
+        {
+          std::ostringstream oss;
+          oss << "DataScopeServerTransaction::createRdExtVarFreeStyleInternal : varname \"" << varName << "\" already exists with a non Sha1Keeper type !";
+          throw Exception(oss.str());
+        }
+      PickelizedPyObjServer *ds3(dynamic_cast<PickelizedPyObjServer *>(ds));
+      if(!ds3)
+        {
+          std::ostringstream oss;
+          oss << "DataScopeServerTransaction::createRdExtVarFreeStyleInternal : varname \"" << varName << "\" already exists with a non PickelizedPyObjServer type !";
+          throw Exception(oss.str());
+        }
+      std::vector<unsigned char> constValueAsCpp;
+      Transaction::FromByteSeqToVB(constValue,constValueAsCpp);
+      SALOME::AutoPyRef newObj(PickelizedPyObjServer::GetPyObjFromPickled(constValueAsCpp,this));
+      if(newObj.isNull())
+        {
+          std::ostringstream oss;
+          oss << "DataScopeServerTransaction::createRdExtVarFreeStyleInternal : varname \"" << varName << "\" already exists but input pickelized object is not loadable !";
+          throw Exception(oss.str());
+        }
+      ds2->checkSame(varName,compareFuncContent,ds3->getPyObj(),newObj);
+    }
+}
+
 void DataScopeServerTransaction::createRdExtInitVarInternal(const std::string& varName, const SALOME::ByteVec& constValue)
 {
   checkNotAlreadyExistingVar(varName);
@@ -567,6 +683,13 @@ SALOME::Transaction_ptr DataScopeServerTransaction::createRdExtVarTransac(const
   return SALOME::Transaction::_narrow(obj);
 }
 
+SALOME::Transaction_ptr DataScopeServerTransaction::createRdExtVarFreeStyleTransac(const char *varName, const SALOME::ByteVec& constValue, const char *compareFuncContent)
+{// no check on varName done here. Will be done on perform
+  TransactionRdExtVarFreeStyleCreate *ret(new TransactionRdExtVarFreeStyleCreate(this,varName,constValue,compareFuncContent));
+  CORBA::Object_var obj(ret->activate());
+  return SALOME::Transaction::_narrow(obj);
+}
+
 SALOME::Transaction_ptr DataScopeServerTransaction::createRdExtInitVarTransac(const char *varName, const SALOME::ByteVec& constValue)
 {
   checkNotAlreadyExistingVar(varName);
@@ -592,24 +715,27 @@ void DataScopeServerTransaction::addWaitKey(KeyWaiter *kw)
 
 void DataScopeServerTransaction::pingKey(PyObject *keyObj)
 {
-  PyObject *cmpObj(getPyCmpFunc());
-  if(!keyObj)
-    throw Exception("ataScopeServerTransaction::pingKey : Key Object is NULL !");
-  PyObject *args(PyTuple_New(2));
-  PyTuple_SetItem(args,0,keyObj); Py_XINCREF(keyObj);
   std::size_t ii(0);
   // this part does nothing except to be sure that in notify key all will be OK.
+  PyObject *args(PyTuple_New(1));
+  PyTuple_SetItem(args,0,keyObj); Py_XINCREF(keyObj);
   for(std::list< KeyWaiter *>::iterator it=_waiting_keys.begin();it!=_waiting_keys.end();it++,ii++)
     {
       PyObject *waitKey((*it)->getKeyPyObj());
-      PyTuple_SetItem(args,1,waitKey); Py_XINCREF(waitKey);
-      PyObject *res(PyObject_CallObject(cmpObj,args));
+      PyObject *meth(PyObject_GetAttrString(waitKey,"__eq__"));
+      if(!meth)
+      {
+         std::ostringstream oss; oss << "DataScopeServerTransaction::pingKey : for object id #" << ii << " no __eq__ in pyobj !";
+         throw Exception(oss.str());
+      }
+      PyObject *res(PyObject_CallObject(meth,args));
+      Py_XDECREF(meth);
       if(res==NULL)
         {
           std::ostringstream oss; oss << "DataScopeServerTransaction::pingKey : for object id #" << ii << " error during cmp(k,wk[i]) !";
           throw Exception(oss.str());
         }
-      PyInt_AsLong(res);
+      PyBool_Check(res);
       if(PyErr_Occurred())
         {
           std::ostringstream oss; oss << "DataScopeServerTransaction::pingKey : for object id #" << ii << " error during interpretation of cmp(k,wk[i]) !";
@@ -617,16 +743,14 @@ void DataScopeServerTransaction::pingKey(PyObject *keyObj)
         }
       Py_XDECREF(res);
     }
+  Py_XDECREF(args);
 }
 
 void DataScopeServerTransaction::notifyKey(const std::string& varName, PyObject *keyObj, PyObject *valueObj)
 {
-  PyObject *cmpObj(getPyCmpFunc());
-  if(!keyObj)
-    throw Exception("DataScopeServerTransaction::notifyKey : MAIN INTERNAL ERROR ! Key Object is NULL !");
-  PyObject *args(PyTuple_New(2));
-  PyTuple_SetItem(args,0,keyObj); Py_XINCREF(keyObj);
   std::size_t ii(0);
+  PyObject *args(PyTuple_New(1));
+  PyTuple_SetItem(args,0,keyObj); Py_XINCREF(keyObj);
   std::list< KeyWaiter *> newList,listOfEltToWakeUp;
   for(std::list< KeyWaiter *>::iterator it=_waiting_keys.begin();it!=_waiting_keys.end();it++,ii++)
     {
@@ -636,25 +760,31 @@ void DataScopeServerTransaction::notifyKey(const std::string& varName, PyObject
           continue;
         }
       PyObject *waitKey((*it)->getKeyPyObj());
-      PyTuple_SetItem(args,1,waitKey); Py_XINCREF(waitKey);
-      PyObject *res(PyObject_CallObject(cmpObj,args));
-      if(res==NULL)
-        {
-          std::ostringstream oss; oss << "DataScopeServerTransaction::notifyKey : MAIN INTERNAL ERROR ! for object id #" << ii << " error during cmp(k,wk[i]) !";
-          throw Exception(oss.str());
-        }
-      long resCpp(PyInt_AsLong(res));
+      PyObject *meth(PyObject_GetAttrString(waitKey,"__eq__"));
+      if(!meth)
+      {
+         std::ostringstream oss; oss << "DataScopeServerTransaction::pingKey : for object id #" << ii << " no __eq__ in pyobj !";
+         throw Exception(oss.str());
+      }
+      PyObject *res(PyObject_CallObject(meth,args));
+      Py_XDECREF(meth);
+      if(!PyBool_Check(res))
+      {
+         std::ostringstream oss; oss << "DataScopeServerTransaction::pingKey : for object id #" << ii << " no __eq__ in pyobj !";
+         throw Exception(oss.str());
+      }
       if(PyErr_Occurred())
         {
           std::ostringstream oss; oss << "DataScopeServerTransaction::notifyKey : MAIN INTERNAL ERROR ! for object id #" << ii << " error during interpretation of cmp(k,wk[i]) !";
           throw Exception(oss.str());
         }
-      Py_XDECREF(res);
-      if(resCpp==0)
+      if(res==Py_True)
         listOfEltToWakeUp.push_back(*it);
       else
         newList.push_back(*it);
+      Py_XDECREF(res);
     }
+  Py_XDECREF(args);
   for(std::list< KeyWaiter *>::iterator it=listOfEltToWakeUp.begin();it!=listOfEltToWakeUp.end();it++)
     (*it)->valueJustCome(valueObj);
   for(std::list< KeyWaiter *>::iterator it=listOfEltToWakeUp.begin();it!=listOfEltToWakeUp.end();it++)
@@ -708,6 +838,16 @@ SALOME::TransactionRdWrAccess_ptr DataScopeServerTransaction::createWorkingVarTr
   return SALOME::TransactionRdWrAccess::_narrow(obj2);
 }
 
+SALOME::Transaction_ptr DataScopeServerTransaction::killVarTransac(const char *varName)
+{
+  std::string varNameCpp(varName);
+  checkExistingVar(varNameCpp);
+  //
+  TransactionKillVar *ret(new TransactionKillVar(this,varName));
+  CORBA::Object_var obj2(ret->activate());
+  return SALOME::Transaction::_narrow(obj2);
+}
+
 SALOME::KeyWaiter_ptr DataScopeServerTransaction::waitForKeyInVar(const char *varName, const SALOME::ByteVec& keyVal)
 {
   PickelizedPyObjServer *pickelObj(checkVarExistingAndDict(varName));
@@ -734,14 +874,33 @@ SALOME::ByteVec *DataScopeServerTransaction::waitForMonoThrRev(SALOME::KeyWaiter
   PortableServer::ServantBase *ret(0);
   try
     {
-      ret=_poa_for_key_waiter->reference_to_servant(kw);
+      ret=_poa_for_key_waiter->reference_to_servant(kw);// Warning ref cnt of ret has been incremented !
+    }
+  catch(...) { ret=0; }
+  KeyWaiter *retc(dynamic_cast<KeyWaiter *>(ret));
+  if(!retc)
+    throw Exception("DataScopeServerTransaction::invokeMonoThr : internal error 1 !");
+  retc->_remove_ref();// restore the counter after _poa_for_key_waiter->reference_to_servant(kw)
+  SALOME::ByteVec *zeRet(retc->waitForMonoThr());
+  retc->enforcedRelease();
+  return zeRet;
+}
+
+SALOME::ByteVec *DataScopeServerTransaction::waitForAndKill(SALOME::KeyWaiter_ptr kw)
+{
+  PortableServer::ServantBase *ret(0);
+  try
+    {
+      ret=_poa_for_key_waiter->reference_to_servant(kw);// Warning ref cnt of ret has been incremented !
     }
   catch(...) { ret=0; }
   KeyWaiter *retc(dynamic_cast<KeyWaiter *>(ret));
   if(!retc)
     throw Exception("DataScopeServerTransaction::invokeMonoThr : internal error 1 !");
-  retc->_remove_ref();
-  return retc->waitForMonoThr();
+  retc->_remove_ref();// restore the counter after _poa_for_key_waiter->reference_to_servant(kw)
+  SALOME::ByteVec *zeRet(retc->waitForAndKill());
+  retc->enforcedRelease();
+  return zeRet;
 }
 
 void DataScopeServerTransaction::atomicApply(const SALOME::ListOfTransaction& transactions)
@@ -785,24 +944,16 @@ void DataScopeServerTransaction::atomicApply(const SALOME::ListOfTransaction& tr
     transactionsCpp[i]->notify();
 }
 
-/*!
- * Returns borrowed reference.
- */
-PyObject *DataScopeServerTransaction::getPyCmpFunc()
+DataScopeServerTransaction::~DataScopeServerTransaction()
 {
-  PyObject *builtins(PyDict_GetItemString(_globals,"__builtins__"));//borrowed
-  if(builtins==NULL)
-    throw Exception("Fail to find reference to builtins !");
-  PyObject *builtins2(PyModule_GetDict(builtins));//borrowed
-  if(builtins2==NULL)
-    throw Exception("Fail to invoke __dict__ on builtins !");
-  PyObject *cmpObj(PyDict_GetItemString(builtins2,"cmp"));
-  if(cmpObj==NULL)
-    throw Exception("Fail to find cmp in __builtins__ !");
-  return cmpObj;
 }
 
-DataScopeServerTransaction::~DataScopeServerTransaction()
+SALOME::RequestSwitcher_ptr DataScopeServerTransaction::getRequestSwitcher()
 {
+  if(_rs.isNull())
+    {
+      _rs=new RequestSwitcher(_orb,this);
+    }
+  CORBA::Object_var obj(_rs->activate());
+  return SALOME::RequestSwitcher::_narrow(obj);
 }
-