1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <Current.h>
6 #include <structmember.h>
7 #include <Connection.h>
8 #include <ObjectAdapter.h>
9 #include <Util.h>
10 #include <Ice/ObjectAdapter.h>
11 
12 using namespace std;
13 using namespace IcePy;
14 
15 namespace IcePy
16 {
17 
18 struct CurrentObject
19 {
20     PyObject_HEAD
21     Ice::Current* current;
22     PyObject* adapter;
23     PyObject* con;
24     PyObject* id;
25     PyObject* facet;
26     PyObject* operation;
27     PyObject* mode;
28     PyObject* ctx;
29     PyObject* requestId;
30     PyObject* encoding;
31 };
32 
33 //
34 // Member identifiers.
35 //
36 const Py_ssize_t CURRENT_ADAPTER    = 0;
37 const Py_ssize_t CURRENT_CONNECTION = 1;
38 const Py_ssize_t CURRENT_ID         = 2;
39 const Py_ssize_t CURRENT_FACET      = 3;
40 const Py_ssize_t CURRENT_OPERATION  = 4;
41 const Py_ssize_t CURRENT_MODE       = 5;
42 const Py_ssize_t CURRENT_CTX        = 6;
43 const Py_ssize_t CURRENT_REQUEST_ID = 7;
44 const Py_ssize_t CURRENT_ENCODING   = 8;
45 
46 }
47 
48 #ifdef WIN32
49 extern "C"
50 #endif
51 static CurrentObject*
currentNew(PyTypeObject * type,PyObject *,PyObject *)52 currentNew(PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwds*/)
53 {
54     CurrentObject* self = reinterpret_cast<CurrentObject*>(type->tp_alloc(type, 0));
55     if(!self)
56     {
57         return 0;
58     }
59 
60     self->current = new Ice::Current;
61     self->adapter = 0;
62     self->con = 0;
63     self->id = 0;
64     self->facet = 0;
65     self->operation = 0;
66     self->mode = 0;
67     self->ctx = 0;
68     self->requestId = 0;
69     self->encoding = 0;
70 
71     return self;
72 }
73 
74 #ifdef WIN32
75 extern "C"
76 #endif
77 static void
currentDealloc(CurrentObject * self)78 currentDealloc(CurrentObject* self)
79 {
80     Py_XDECREF(self->adapter);
81     Py_XDECREF(self->con);
82     Py_XDECREF(self->id);
83     Py_XDECREF(self->facet);
84     Py_XDECREF(self->operation);
85     Py_XDECREF(self->mode);
86     Py_XDECREF(self->ctx);
87     Py_XDECREF(self->requestId);
88     Py_XDECREF(self->encoding);
89     delete self->current;
90     Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
91 }
92 
93 #ifdef WIN32
94 extern "C"
95 #endif
96 static PyObject*
currentGetter(CurrentObject * self,void * closure)97 currentGetter(CurrentObject* self, void* closure)
98 {
99     //
100     // This function intercepts requests for attributes of a Current object. We use this
101     // lazy initialization in order to minimize the cost of translating Ice::Current into a
102     // Python object for every upcall.
103     //
104     PyObject* result = 0;
105 
106     assert(self->current);
107 
108     Py_ssize_t field = reinterpret_cast<Py_ssize_t>(closure);
109     switch(field)
110     {
111     case CURRENT_ADAPTER:
112     {
113         if(!self->adapter)
114         {
115             self->adapter = wrapObjectAdapter(self->current->adapter);
116             if(!self->adapter)
117             {
118                 return 0;
119             }
120         }
121         Py_INCREF(self->adapter);
122         result = self->adapter;
123         break;
124     }
125     case CURRENT_CONNECTION:
126     {
127         if(!self->con)
128         {
129             self->con = createConnection(self->current->con, self->current->adapter->getCommunicator());
130             if(!self->con)
131             {
132                 return 0;
133             }
134         }
135         Py_INCREF(self->con);
136         result = self->con;
137         break;
138     }
139     case CURRENT_ID:
140     {
141         if(!self->id)
142         {
143             self->id = createIdentity(self->current->id);
144         }
145         Py_INCREF(self->id);
146         result = self->id;
147         break;
148     }
149     case CURRENT_FACET:
150     {
151         if(!self->facet)
152         {
153             self->facet = createString(self->current->facet);
154         }
155         Py_INCREF(self->facet);
156         result = self->facet;
157         break;
158     }
159     case CURRENT_OPERATION:
160     {
161         if(!self->operation)
162         {
163             self->operation = createString(self->current->operation);
164         }
165         Py_INCREF(self->operation);
166         result = self->operation;
167         break;
168     }
169     case CURRENT_MODE:
170     {
171         if(!self->mode)
172         {
173             PyObject* type = lookupType("Ice.OperationMode");
174             assert(type);
175             const char* enumerator = 0;
176             switch(self->current->mode)
177             {
178             case Ice::Normal:
179                 enumerator = "Normal";
180                 break;
181             case Ice::Nonmutating:
182                 enumerator = "Nonmutating";
183                 break;
184             case Ice::Idempotent:
185                 enumerator = "Idempotent";
186                 break;
187             }
188             self->mode = getAttr(type, enumerator, false);
189             assert(self->mode);
190         }
191         Py_INCREF(self->mode);
192         result = self->mode;
193         break;
194     }
195     case CURRENT_CTX:
196     {
197         if(!self->ctx)
198         {
199             self->ctx = PyDict_New();
200             if(self->ctx && !contextToDictionary(self->current->ctx, self->ctx))
201             {
202                 Py_DECREF(self->ctx);
203                 self->ctx = 0;
204                 break;
205             }
206         }
207         Py_INCREF(self->ctx);
208         result = self->ctx;
209         break;
210     }
211     case CURRENT_REQUEST_ID:
212     {
213         if(!self->requestId)
214         {
215             self->requestId = PyLong_FromLong(self->current->requestId);
216             assert(self->requestId);
217         }
218         Py_INCREF(self->requestId);
219         result = self->requestId;
220         break;
221     }
222     case CURRENT_ENCODING:
223     {
224         if(!self->encoding)
225         {
226             self->encoding = IcePy::createEncodingVersion(self->current->encoding);
227             assert(self->encoding);
228         }
229         Py_INCREF(self->encoding);
230         result = self->encoding;
231         break;
232     }
233     }
234 
235     return result;
236 }
237 
238 static PyGetSetDef CurrentGetSetters[] =
239 {
240     { STRCAST("adapter"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("object adapter"),
241       reinterpret_cast<void*>(CURRENT_ADAPTER) },
242     { STRCAST("con"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("connection info"),
243       reinterpret_cast<void*>(CURRENT_CONNECTION) },
244     { STRCAST("id"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("identity"),
245       reinterpret_cast<void*>(CURRENT_ID) },
246     { STRCAST("facet"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("facet name"),
247       reinterpret_cast<void*>(CURRENT_FACET) },
248     { STRCAST("operation"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("operation name"),
249       reinterpret_cast<void*>(CURRENT_OPERATION) },
250     { STRCAST("mode"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("operation mode"),
251       reinterpret_cast<void*>(CURRENT_MODE) },
252     { STRCAST("ctx"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("context"),
253       reinterpret_cast<void*>(CURRENT_CTX) },
254     { STRCAST("requestId"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("requestId"),
255       reinterpret_cast<void*>(CURRENT_REQUEST_ID) },
256     { STRCAST("encoding"), reinterpret_cast<getter>(currentGetter), 0, STRCAST("encoding"),
257       reinterpret_cast<void*>(CURRENT_ENCODING) },
258     { 0 }  /* Sentinel */
259 };
260 
261 namespace IcePy
262 {
263 
264 PyTypeObject CurrentType =
265 {
266     /* The ob_type field must be initialized in the module init function
267      * to be portable to Windows without using C++. */
268     PyVarObject_HEAD_INIT(0, 0)
269     STRCAST("IcePy.Current"),        /* tp_name */
270     sizeof(CurrentObject),           /* tp_basicsize */
271     0,                               /* tp_itemsize */
272     /* methods */
273     reinterpret_cast<destructor>(currentDealloc), /* tp_dealloc */
274     0,                               /* tp_print */
275     0,                               /* tp_getattr */
276     0,                               /* tp_setattr */
277     0,                               /* tp_reserved */
278     0,                               /* tp_repr */
279     0,                               /* tp_as_number */
280     0,                               /* tp_as_sequence */
281     0,                               /* tp_as_mapping */
282     0,                               /* tp_hash */
283     0,                               /* tp_call */
284     0,                               /* tp_str */
285     0,                               /* tp_getattro */
286     0,                               /* tp_setattro */
287     0,                               /* tp_as_buffer */
288     Py_TPFLAGS_DEFAULT,              /* tp_flags */
289     0,                               /* tp_doc */
290     0,                               /* tp_traverse */
291     0,                               /* tp_clear */
292     0,                               /* tp_richcompare */
293     0,                               /* tp_weaklistoffset */
294     0,                               /* tp_iter */
295     0,                               /* tp_iternext */
296     0,                               /* tp_methods */
297     0,                               /* tp_members */
298     CurrentGetSetters,               /* tp_getset */
299     0,                               /* tp_base */
300     0,                               /* tp_dict */
301     0,                               /* tp_descr_get */
302     0,                               /* tp_descr_set */
303     0,                               /* tp_dictoffset */
304     0,                               /* tp_init */
305     0,                               /* tp_alloc */
306     reinterpret_cast<newfunc>(currentNew), /* tp_new */
307     0,                               /* tp_free */
308     0,                               /* tp_is_gc */
309 };
310 
311 }
312 
313 bool
initCurrent(PyObject * module)314 IcePy::initCurrent(PyObject* module)
315 {
316     if(PyType_Ready(&CurrentType) < 0)
317     {
318         return false;
319     }
320     PyTypeObject* type = &CurrentType; // Necessary to prevent GCC's strict-alias warnings.
321     if(PyModule_AddObject(module, STRCAST("Current"), reinterpret_cast<PyObject*>(type)) < 0)
322     {
323         return false;
324     }
325 
326     return true;
327 }
328 
329 PyObject*
createCurrent(const Ice::Current & current)330 IcePy::createCurrent(const Ice::Current& current)
331 {
332     //
333     // Return an instance of IcePy.Current to hold the current information.
334     //
335     CurrentObject* obj = currentNew(&CurrentType, 0, 0);
336     if(obj)
337     {
338         *obj->current = current;
339     }
340     return reinterpret_cast<PyObject*>(obj);
341 }
342