Salome HOME
Copyrights update 2015.
[modules/kernel.git] / src / SALOMESDS / SALOMESDS_PickelizedPyObjServer.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony GEAY (EDF R&D)
20
21 #include "SALOMESDS_PickelizedPyObjServer.hxx"
22 #include "SALOMESDS_DataScopeServer.hxx"
23 #include "SALOMESDS_Exception.hxx"
24
25 #include <iostream>
26 #include <sstream>
27
28 using namespace SALOMESDS;
29
30 PickelizedPyObjServer::PickelizedPyObjServer(DataScopeServer *father, const std::string& varName, const SALOME::ByteVec& value):BasicDataServer(father,varName),_self(0)
31 {
32   setSerializedContentInternal(value);
33 }
34
35 //! obj is consumed
36 PickelizedPyObjServer::PickelizedPyObjServer(DataScopeServer *father, const std::string& varName, PyObject *obj):BasicDataServer(father,varName),_self(0)
37 {
38   setNewPyObj(obj);
39 }
40
41 PickelizedPyObjServer::~PickelizedPyObjServer()
42 {
43   Py_XDECREF(_self);
44 }
45
46 /*!
47  * Called remotely -> to protect against throw
48  */
49 SALOME::ByteVec *PickelizedPyObjServer::fetchSerializedContent()
50 {
51   Py_XINCREF(_self);//because pickelize consume _self
52   return FromCppToByteSeq(pickelize(_self));
53 }
54
55 void PickelizedPyObjServer::FromByteSeqToCpp(const SALOME::ByteVec& bsToBeConv, std::string& ret)
56 {
57   std::size_t sz(bsToBeConv.length());
58   ret.resize(sz,' ');
59   char *buf(const_cast<char *>(ret.c_str()));
60   for(std::size_t i=0;i<sz;i++)
61     buf[i]=bsToBeConv[i];
62 }
63
64 SALOME::ByteVec *PickelizedPyObjServer::FromCppToByteSeq(const std::string& strToBeConv)
65 {
66   SALOME::ByteVec *ret(new SALOME::ByteVec);
67   const char *buf(strToBeConv.c_str());
68   std::size_t sz(strToBeConv.size());
69   ret->length(sz);
70   for(std::size_t i=0;i<sz;i++)
71     (*ret)[i]=buf[i];
72   return ret;
73 }
74
75 //! New reference returned
76 PyObject *PickelizedPyObjServer::getPyObjFromPickled(const std::string& pickledData)
77 {
78   std::size_t sz(pickledData.size());
79   PyObject *pickledDataPy(PyString_FromStringAndSize(NULL,sz));// agy : do not use PyString_FromString because std::string hides a vector of byte.
80   char *buf(PyString_AsString(pickledDataPy));// this buf can be used thanks to python documentation.
81   const char *inBuf(pickledData.c_str());
82   std::copy(inBuf,inBuf+sz,buf);
83   PyObject *selfMeth(PyObject_GetAttrString(_father->getPickler(),"loads"));
84   PyObject *args(PyTuple_New(1)); PyTuple_SetItem(args,0,pickledDataPy);
85   PyObject *ret(PyObject_CallObject(selfMeth,args));
86   Py_XDECREF(args);
87   Py_XDECREF(selfMeth);
88   return ret;
89 }
90
91 //! obj is consumed by this method.
92 std::string PickelizedPyObjServer::pickelize(PyObject *obj)
93 {
94   PyObject *args(PyTuple_New(2));
95   PyTuple_SetItem(args,0,obj);
96   PyTuple_SetItem(args,1,PyInt_FromLong(2));// because "assert(cPickle.HIGHEST_PROTOCOL is 2)"
97   PyObject *selfMeth(PyObject_GetAttrString(_father->getPickler(),"dumps"));
98   PyObject *retPy(PyObject_CallObject(selfMeth,args));
99   Py_XDECREF(selfMeth);
100   Py_XDECREF(args);
101   std::size_t sz(PyString_Size(retPy));
102   std::string ret(sz,'\0');
103   const char *buf(PyString_AsString(retPy));
104   char *inBuf(const_cast<char *>(ret.c_str()));
105   for(std::size_t i=0;i<sz;i++)
106     inBuf[i]=buf[i];
107   Py_XDECREF(retPy);
108   return ret;
109 }
110
111 //! obj is consumed by this method.
112 void PickelizedPyObjServer::setNewPyObj(PyObject *obj)
113 {
114   if(!obj)
115     throw Exception("PickelizedPyObjServer::setNewPyObj : trying to assign a NULL pyobject in this !");
116   if(obj==_self)
117     return ;
118   if(PyList_Check(obj)==0 && PyDict_Check(obj)==0 && PyTuple_Check(obj)==0 && PyString_Check(obj)==0 && PyInt_Check(obj)==0 && PyBool_Check(obj)==0 && PyFloat_Check(obj)==0 && obj!=Py_None)
119     throw Exception("PickelizedPyObjServer::setNewPyObj : Supported python types are [list,tuple,dict,str,int,bool,float,None] !");
120   if(_self)
121     {
122       PyObject *selfType(PyObject_Type(_self));
123       if(PyObject_IsInstance(obj,selfType)!=1)
124         {
125           Py_XDECREF(obj);
126           Py_XDECREF(selfType);
127           throw Exception("PickelizedPyObjServer::setNewPyObj : type of new object is not the same than those previously set !");
128         }
129       else
130         Py_XDECREF(selfType);
131     }
132   Py_XDECREF(_self);
133   _self=obj;
134 }
135
136 void PickelizedPyObjServer::setSerializedContentInternal(const SALOME::ByteVec& newValue)
137 {
138   std::string data;
139   FromByteSeqToCpp(newValue,data);
140   setNewPyObj(getPyObjFromPickled(data));
141 }
142
143 PyObject *PickelizedPyObjServer::CreateDftObjFromType(PyObject *globals, const std::string& typeName)
144 {
145   PyObject *builtins(PyDict_GetItemString(globals,"__builtins__"));
146   if(!builtins)
147     throw Exception("PickelizedPyObjServer constructor : no __builtins__ in globals !");
148   PyObject *builtins2(PyModule_GetDict(builtins));
149   if(!builtins2)
150     throw Exception("PickelizedPyObjServer constructor : internal error fail to invoke __dict__ on __builtins__ !");
151   PyObject *tmp(PyDict_GetItemString(builtins2,typeName.c_str()));
152   if(!tmp)
153     {
154       std::ostringstream oss; oss << "PickelizedPyObjServer::CreateDftObjFromType : Invalid type name \"" << typeName << "\" !";
155       throw Exception(oss.str());
156     }
157   PyObject *args(PyTuple_New(0));
158   PyObject *ret(PyObject_CallObject(tmp,args));
159   Py_XDECREF(args);
160   return ret;
161 }