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