1 // -*- Mode: C++; -*-
2 //                            Package   : omniORBpy
3 // pyObjectRef.cc             Created on: 1999/07/29
4 //                            Author    : Duncan Grisby (dpg1)
5 //
6 //    Copyright (C) 2002-2014 Apasphere Ltd
7 //    Copyright (C) 1999 AT&T Laboratories Cambridge
8 //
9 //    This file is part of the omniORBpy library
10 //
11 //    The omniORBpy library is free software; you can redistribute it
12 //    and/or modify it under the terms of the GNU Lesser General
13 //    Public License as published by the Free Software Foundation;
14 //    either version 2.1 of the License, or (at your option) any later
15 //    version.
16 //
17 //    This library is distributed in the hope that it will be useful,
18 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 //    GNU Lesser General Public License for more details.
21 //
22 //    You should have received a copy of the GNU Lesser General Public
23 //    License along with this library. If not, see http://www.gnu.org/licenses/
24 //
25 // Description:
26 //    Versions of ORB object ref functions which deal with Python
27 //    objects, rather than C++ objects
28 
29 #include <omnipy.h>
30 #include <omniORBpy.h>
31 
32 // Internal omniORB interfaces
33 #include <objectTable.h>
34 #include <remoteIdentity.h>
35 #include <inProcessIdentity.h>
36 #include <objectAdapter.h>
37 #include <omniORB4/omniURI.h>
38 #include <giopStrand.h>
39 #include <giopStream.h>
40 #include <omniCurrent.h>
41 #include <poaimpl.h>
42 
43 OMNI_USING_NAMESPACE(omni)
44 
45 #if defined(HAS_Cplusplus_Namespace)
46 using omniORB::operator==;
47 #endif
48 
49 
50 class Py_omniObjRef : public virtual CORBA::Object,
51 		      public virtual omniObjRef
52 {
53 public:
Py_omniObjRef(const char * repoId,omniIOR * ior,omniIdentity * id)54   Py_omniObjRef(const char*        repoId,
55 		omniIOR*           ior,
56 		omniIdentity*      id)
57 
58     : omniObjRef(repoId, ior, id)
59   {
60     _PR_setobj(this);
61   }
~Py_omniObjRef()62   virtual ~Py_omniObjRef() { }
63 
64   virtual const char* _localServantTarget();
65 
66 private:
67   virtual void* _ptrToObjRef(const char* target);
68 
69   // Not implemented:
70   Py_omniObjRef(const Py_omniObjRef&);
71   Py_omniObjRef& operator=(const Py_omniObjRef&);
72 };
73 
74 const char*
_localServantTarget()75 Py_omniObjRef::_localServantTarget()
76 {
77   return omniPy::string_Py_omniServant;
78 }
79 
80 void*
_ptrToObjRef(const char * target)81 Py_omniObjRef::_ptrToObjRef(const char* target)
82 {
83   if (omni::ptrStrMatch(target, omniPy::string_Py_omniObjRef))
84     return (Py_omniObjRef*)this;
85 
86   if (omni::ptrStrMatch(target, CORBA::Object::_PD_repoId))
87     return (CORBA::Object_ptr)this;
88 
89   return 0;
90 }
91 
92 
93 PyObject*
createPyCorbaObjRef(const char * targetRepoId,const CORBA::Object_ptr objref)94 omniPy::createPyCorbaObjRef(const char*             targetRepoId,
95 			    const CORBA::Object_ptr objref)
96 {
97   if (CORBA::is_nil(objref)) {
98     Py_INCREF(Py_None);
99     return Py_None;
100   }
101   if (objref->_NP_is_pseudo())
102     return createPyPseudoObjRef(objref);
103 
104   omniObjRef* ooref = objref->_PR_getobj();
105 
106   const char*    actualRepoId = ooref->_mostDerivedRepoId();
107   PyObject*      objrefClass;
108   CORBA::Boolean fullTypeUnknown = 0;
109 
110   // Try to find objref class for most derived type:
111   objrefClass = PyDict_GetItemString(pyomniORBobjrefMap, (char*)actualRepoId);
112 
113   if (targetRepoId &&
114       !omni::ptrStrMatch(targetRepoId, actualRepoId) &&
115       !omni::ptrStrMatch(targetRepoId, CORBA::Object::_PD_repoId)) {
116 
117     // targetRepoId is not plain CORBA::Object, and is different from
118     // actualRepoId
119 
120     if (objrefClass) {
121       // We've got an objref class for the most derived type. Is it a
122       // subclass of the target type?
123       PyObject* targetClass = PyDict_GetItemString(pyomniORBobjrefMap,
124 						   (char*)targetRepoId);
125 
126       if (!PyObject_IsSubclass(objrefClass, targetClass)) {
127 	// Actual type is not derived from the target. Surprisingly
128 	// enough, this is valid -- the repoId in an object reference
129 	// is not necessarily that of the most derived type for the
130 	// object. If we are expecting interface A, and actually get
131 	// unrelated B, the object might actually have interface C,
132 	// derived from both A and B.
133 	//
134 	// In this situation, we must create an object reference of
135 	// the target type, not the object's claimed type.
136 	objrefClass     = targetClass;
137 	fullTypeUnknown = 1;
138       }
139     }
140     else {
141       // No objref class for the most derived type -- try to find one for
142       // the target type:
143       objrefClass     = PyDict_GetItemString(pyomniORBobjrefMap,
144 					     (char*)targetRepoId);
145       fullTypeUnknown = 1;
146     }
147   }
148   if (!objrefClass) {
149     // No target type, or stub code bug:
150     objrefClass     = PyObject_GetAttrString(pyCORBAmodule, (char*)"Object");
151     fullTypeUnknown = 1;
152   }
153 
154   OMNIORB_ASSERT(objrefClass); // Couldn't even find CORBA.Object!
155 
156   omniPy::PyRefHolder args(PyTuple_New(1));
157   PyTuple_SET_ITEM(args, 0, createPyObjRefObject(objref));
158 
159   PyObject* pyobjref = PyObject_CallObject(objrefClass, args);
160 
161   if (!pyobjref) {
162     // Oh dear -- return the error to the program
163     return 0;
164   }
165 
166   if (fullTypeUnknown) {
167     PyObject* idstr = String_FromString(actualRepoId);
168     PyObject_SetAttrString(pyobjref, (char*)"_NP_RepositoryId", idstr);
169     Py_DECREF(idstr);
170   }
171 
172   return pyobjref;
173 }
174 
175 
176 PyObject*
createPyPseudoObjRef(const CORBA::Object_ptr objref)177 omniPy::createPyPseudoObjRef(const CORBA::Object_ptr objref)
178 {
179   {
180     CORBA::ORB_var orbp = CORBA::ORB::_narrow(objref);
181     if (!CORBA::is_nil(orbp)) {
182       OMNIORB_ASSERT(omniPy::orb);
183       return PyObject_GetAttrString(omniPy::pyomniORBmodule, (char*)"orb");
184     }
185   }
186   {
187     PortableServer::POA_var poa = PortableServer::POA::_narrow(objref);
188     if (!CORBA::is_nil(poa)) return createPyPOAObject(poa);
189   }
190   {
191     PortableServer::POAManager_var pm =
192       PortableServer::POAManager::_narrow(objref);
193     if (!CORBA::is_nil(pm)) return createPyPOAManagerObject(pm);
194   }
195   {
196     PortableServer::Current_var pc = PortableServer::Current::_narrow(objref);
197     if (!CORBA::is_nil(pc)) return createPyPOACurrentObject(pc);
198   }
199 
200   {
201     // No built in converter. Try the list of registered external functions
202     int len = PySequence_Length(omniPy::py_pseudoFns);
203     for (int i=0; i < len; i++) {
204       PyObject* pyf = PySequence_GetItem(omniPy::py_pseudoFns, i);
205 
206 #if (PY_VERSION_HEX <= 0x03000000)
207 
208       if (!PyCObject_Check(pyf)) {
209 	omniORB::logs(1, "WARNING: Entry in _omnipy.pseudoFns "
210 		      "is not a PyCObject.");
211 	continue;
212       }
213       omniORBpyPseudoFn f = (omniORBpyPseudoFn)PyCObject_AsVoidPtr(pyf);
214 #else
215       if (!PyCapsule_CheckExact(pyf)) {
216 	omniORB::logs(1, "WARNING: Entry in _omnipy.pseudoFns "
217 		      "is not a PyCapsule.");
218 	continue;
219       }
220       omniORBpyPseudoFn f = (omniORBpyPseudoFn)PyCapsule_GetPointer(pyf, 0);
221 #endif
222       PyObject* ret = f(objref);
223       if (ret)
224 	return ret;
225     }
226   };
227 
228   try {
229     // Use OMNIORB_THROW to get a nice trace message
230     OMNIORB_THROW(INV_OBJREF, INV_OBJREF_NoPythonTypeForPseudoObj,
231 		  CORBA::COMPLETED_NO);
232   }
233   OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
234   return 0;
235 }
236 
237 
238 
239 omniObjRef*
createObjRef(const char * targetRepoId,omniIOR * ior,CORBA::Boolean locked,omniIdentity * id,CORBA::Boolean type_verified,CORBA::Boolean is_forwarded)240 omniPy::createObjRef(const char*    	targetRepoId,
241 		     omniIOR*       	ior,
242 		     CORBA::Boolean 	locked,
243 		     omniIdentity*  	id,
244 		     CORBA::Boolean     type_verified,
245 		     CORBA::Boolean     is_forwarded)
246 {
247   ASSERT_OMNI_TRACEDMUTEX_HELD(*omni::internalLock, locked);
248   OMNIORB_ASSERT(targetRepoId);
249   OMNIORB_ASSERT(ior);
250 
251   CORBA::Boolean called_create = 0;
252 
253   if (!id) {
254     ior->duplicate();  // consumed by createIdentity
255     id = omni::createIdentity(ior, omniPy::string_Py_omniServant, locked);
256     called_create = 1;
257     if (!id) {
258       ior->release();
259       return 0;
260     }
261   }
262 
263   if (omniORB::trace(10)) {
264     omniORB::logger l;
265     l << "Creating Python ref to ";
266     if      (omniLocalIdentity    ::downcast(id)) l << "local";
267     else if (omniInProcessIdentity::downcast(id)) l << "in process";
268     else if (omniRemoteIdentity   ::downcast(id)) l << "remote";
269     else                                          l << "unknown";
270     l << ": " << id << "\n"
271       " target id      : " << targetRepoId << "\n"
272       " most derived id: " << (const char*)ior->repositoryID() << "\n";
273   }
274 
275   omniObjRef* objref = new Py_omniObjRef(targetRepoId, ior, id);
276 
277   if (!type_verified &&
278       !omni::ptrStrMatch(targetRepoId, CORBA::Object::_PD_repoId)) {
279 
280     objref->pd_flags.type_verified = 0;
281   }
282 
283   if (is_forwarded) {
284     omniORB::logs(10, "Reference has been forwarded.");
285     objref->pd_flags.forward_location = 1;
286   }
287 
288   {
289     omni_optional_lock sync(*omni::internalLock, locked, locked);
290     id->gainRef(objref);
291     if (called_create)
292       id->loseRef();
293   }
294 
295   if (orbParameters::persistentId.length()) {
296     // Check to see if we need to re-write the IOR.
297 
298     omniIOR::IORExtraInfoList& extra = ior->getIORInfo()->extraInfo();
299 
300     for (CORBA::ULong index = 0; index < extra.length(); index++) {
301 
302       if (extra[index]->compid == IOP::TAG_OMNIORB_PERSISTENT_ID)
303 
304 	if (!id->inThisAddressSpace()) {
305 
306 	  omniORB::logs(15, "Re-write local persistent object reference.");
307 
308 	  omniObjRef* new_objref;
309 	  omniIORHints hints(0);
310 	  {
311 	    omni_optional_lock sync(*internalLock, locked, locked);
312 
313 	    omniIOR* new_ior = new omniIOR(ior->repositoryID(),
314 					   id->key(), id->keysize(), hints);
315 
316 	    new_objref = createObjRef(targetRepoId, new_ior,
317 				      1, 0, type_verified);
318 	  }
319 	  releaseObjRef(objref);
320 	  objref = new_objref;
321 	}
322       break;
323     }
324   }
325   return objref;
326 }
327 
328 
329 omniObjRef*
createLocalObjRef(const char * mostDerivedRepoId,const char * targetRepoId,omniObjTableEntry * entry,omniObjRef * orig_ref,CORBA::Boolean type_verified)330 omniPy::createLocalObjRef(const char*         mostDerivedRepoId,
331 			  const char*         targetRepoId,
332 			  omniObjTableEntry*  entry,
333 			  omniObjRef*         orig_ref,
334 			  CORBA::Boolean      type_verified)
335 {
336   ASSERT_OMNI_TRACEDMUTEX_HELD(*omni::internalLock, 1);
337   OMNIORB_ASSERT(targetRepoId);
338   OMNIORB_ASSERT(entry);
339 
340   // See if a suitable reference exists in the local ref list.
341   // Suitable means having the same most-derived-intf-repo-id, and
342   // also supporting the <targetRepoId>.
343   {
344     omniObjRef* objref;
345 
346     omnivector<omniObjRef*>::iterator i    = entry->objRefs().begin();
347     omnivector<omniObjRef*>::iterator last = entry->objRefs().end();
348 
349     for (; i != last; i++) {
350       objref = *i;
351 
352       if (omni::ptrStrMatch(mostDerivedRepoId, objref->_mostDerivedRepoId()) &&
353 	  objref->_ptrToObjRef(omniPy::string_Py_omniObjRef) &&
354 	  omni::ptrStrMatch(targetRepoId, objref->pd_intfRepoId)) {
355 
356 	// We just need to check that the ref count is not zero here,
357 	// 'cos if it is then the objref is about to be deleted!
358 	// See omni::releaseObjRef().
359 
360 	omni::objref_rc_lock->lock();
361 	int dying = objref->pd_refCount == 0;
362 	if( !dying )  objref->pd_refCount++;
363 	omni::objref_rc_lock->unlock();
364 
365 	if( !dying ) {
366 	  omniORB::logs(15, "omniPy::createLocalObjRef -- reusing "
367 			"reference from local ref list.");
368 	  return objref;
369 	}
370       }
371     }
372   }
373   // Reach here if we have to create a new objref.
374   omniIOR* ior = orig_ref->_getIOR();
375   return omniPy::createObjRef(targetRepoId, ior, 1, entry, type_verified);
376 }
377 
378 omniObjRef*
createLocalObjRef(const char * mostDerivedRepoId,const char * targetRepoId,const _CORBA_Octet * key,int keysize,omniObjRef * orig_ref,CORBA::Boolean type_verified)379 omniPy::createLocalObjRef(const char* 	      mostDerivedRepoId,
380 			  const char* 	      targetRepoId,
381 			  const _CORBA_Octet* key,
382 			  int                 keysize,
383 			  omniObjRef*         orig_ref,
384 			  CORBA::Boolean      type_verified)
385 {
386   ASSERT_OMNI_TRACEDMUTEX_HELD(*omni::internalLock, 1);
387   OMNIORB_ASSERT(targetRepoId);
388   OMNIORB_ASSERT(key && keysize);
389 
390   // See if there's a suitable entry in the object table
391   CORBA::ULong hashv = omni::hash(key, keysize);
392 
393   omniObjTableEntry* entry = omniObjTable::locateActive(key, keysize,
394 							hashv, 0);
395 
396   if (entry)
397     return createLocalObjRef(mostDerivedRepoId, targetRepoId,
398 			     entry, orig_ref, type_verified);
399 
400   omniIOR* ior = orig_ref->_getIOR();
401   return createObjRef(targetRepoId,ior,1,0,type_verified);
402 }
403 
404 
405 
406 
407 CORBA::Object_ptr
makeLocalObjRef(const char * targetRepoId,const CORBA::Object_ptr objref)408 omniPy::makeLocalObjRef(const char* targetRepoId,
409 			const CORBA::Object_ptr objref)
410 {
411   ASSERT_OMNI_TRACEDMUTEX_HELD(*omni::internalLock, 0);
412 
413   omniObjRef* ooref = objref->_PR_getobj();
414   omniObjRef* newooref;
415 
416   {
417     omni_tracedmutex_lock sync(*omni::internalLock);
418 
419     omniObjTableEntry* entry = omniObjTableEntry::downcast(ooref->_identity());
420 
421     if (entry)
422       newooref = omniPy::createLocalObjRef(ooref->_mostDerivedRepoId(),
423 					   targetRepoId, entry, ooref, 1);
424     else
425       newooref = omniPy::createLocalObjRef(ooref->_mostDerivedRepoId(),
426 					   targetRepoId,
427 					   ooref->_identity()->key(),
428 					   ooref->_identity()->keysize(),
429 					   ooref, 1);
430   }
431   return (CORBA::Object_ptr)newooref->_ptrToObjRef(CORBA::Object::_PD_repoId);
432 }
433 
434 
435 PyObject*
copyObjRefArgument(PyObject * pytargetRepoId,PyObject * pyobjref,CORBA::CompletionStatus compstatus)436 omniPy::copyObjRefArgument(PyObject* pytargetRepoId, PyObject* pyobjref,
437 			   CORBA::CompletionStatus compstatus)
438 {
439   if (pyobjref == Py_None) {
440     // Nil objref
441     Py_INCREF(Py_None);
442     return Py_None;
443   }
444   CORBA::Object_ptr objref = getObjRef(pyobjref);
445   if (!objref) {
446     // Not an objref
447     THROW_PY_BAD_PARAM(BAD_PARAM_WrongPythonType, compstatus,
448 		       omniPy::formatString("Expecting object reference, "
449 					    "got %r",
450 					    "O", pyobjref->ob_type));
451   }
452 
453   // To copy an object reference, we have to take a number of things
454   // into account. When the C++ object reference was created, it was
455   // initialised with a most-derived repoId and a target repoId. If we
456   // knew that the most-derived interface is compatible with the
457   // target, then the Python objref is of the most derived type. If we
458   // did not know the most-derived interface, or we did know it and
459   // believed it to be incompatible with the target, then the Python
460   // objref is of the target type, and it has a string attribute named
461   // "_NP_RepositoryId" containing the most derived repoId.
462   //
463   // Now, as we are copying this objref, we have a target repoId,
464   // which is possibly different from the objref's original target.
465   // It's also possible that some time after we created the Python
466   // objref, some new stubs were imported, so we now know about the
467   // objref's most derived type when before we didn't.
468   //
469   // So, to copy the reference, we first see if the Python objref has
470   // an attribute named "_NP_RepositoryId". If it does, all bets are
471   // off, and we have to create a new C++ objref from scratch. If it
472   // doesn't have the attribute, we look to see if the objref's class
473   // is a subclass of the target objref class (or the same class). If
474   // so, we can just incref the existing Python objref and return it;
475   // if not, we have to build a new C++ objref.
476 
477   if (!PyObject_HasAttrString(pyobjref, (char*)"_NP_RepositoryId")) {
478 
479     PyObject* targetClass = PyDict_GetItem(pyomniORBobjrefMap,
480 					   pytargetRepoId);
481     OMNIORB_ASSERT(targetClass);
482 
483     if (PyObject_IsInstance(pyobjref, targetClass)) {
484       Py_INCREF(pyobjref);
485       return pyobjref;
486     }
487   }
488   // Create new C++ and Python objrefs with the right target type
489   omniObjRef* ooref        = objref->_PR_getobj();
490   const char* targetRepoId = String_AS_STRING(pytargetRepoId);
491 
492   if (targetRepoId[0] == '\0') targetRepoId = CORBA::Object::_PD_repoId;
493 
494   omniObjRef* newooref;
495   {
496     omniPy::InterpreterUnlocker _u;
497     newooref = omniPy::createObjRef(targetRepoId, ooref->_getIOR(), 0, 0);
498   }
499   PyObject* r = createPyCorbaObjRef(targetRepoId,
500 				    (CORBA::Object_ptr)newooref->
501 				      _ptrToObjRef(CORBA::Object::_PD_repoId));
502   if (!r) {
503     if (omniORB::trace(1)) {
504       {
505 	omniORB::logger l;
506 	l <<
507 	  "Caught an unexpected Python exception trying to create an "
508 	  "object reference.\n";
509       }
510       PyErr_Print();
511     }
512     PyErr_Clear();
513     OMNIORB_THROW(INTERNAL, 0, compstatus);
514   }
515   return r;
516 }
517 
518 
519 CORBA::Object_ptr
stringToObject(const char * uri)520 omniPy::stringToObject(const char* uri)
521 {
522   CORBA::Object_ptr cxxobj;
523   omniObjRef* objref;
524 
525   {
526     omniPy::InterpreterUnlocker _u;
527     cxxobj = omniURI::stringToObject(uri);
528 
529     if (CORBA::is_nil(cxxobj) || cxxobj->_NP_is_pseudo()) {
530       return cxxobj;
531     }
532     omniObjRef* cxxobjref = cxxobj->_PR_getobj();
533 
534     objref = omniPy::createObjRef(CORBA::Object::_PD_repoId,
535 				  cxxobjref->_getIOR(), 0, 0);
536     CORBA::release(cxxobj);
537   }
538   return (CORBA::Object_ptr)objref->_ptrToObjRef(CORBA::Object::_PD_repoId);
539 }
540 
541 
542 CORBA::Object_ptr
UnMarshalObjRef(const char * repoId,cdrStream & s)543 omniPy::UnMarshalObjRef(const char* repoId, cdrStream& s)
544 {
545   CORBA::String_var           id;
546   IOP::TaggedProfileList_var  profiles;
547 
548   id = IOP::IOR::unmarshaltype_id(s);
549 
550   profiles = new IOP::TaggedProfileList();
551   (IOP::TaggedProfileList&)profiles <<= s;
552 
553   if (profiles->length() == 0 && strlen(id) == 0) {
554     // Nil object reference
555     return CORBA::Object::_nil();
556   }
557   else {
558     omniPy::InterpreterUnlocker _u;
559 
560     // It is possible that we reach here with the id string = '\0'.
561     // That is alright because the actual type of the object will be
562     // verified using _is_a() at the first invocation on the object.
563     //
564     // Apparently, some ORBs such as ExperSoft's do that. Furthermore,
565     // this has been accepted as a valid behaviour in GIOP 1.1/IIOP 1.1.
566     //
567     omniIOR* ior = new omniIOR(id._retn(),profiles._retn());
568 
569     giopStream* gs = giopStream::downcast(&s);
570     if (gs) {
571       giopStrand& g = gs->strand();
572       if (g.isBiDir() && !g.isClient()) {
573 	// Check the POA policy to see if the servant's POA is willing
574 	// to use bidirectional on its callback objects.
575 	omniCurrent*        current = omniCurrent::get();
576 	omniCallDescriptor* desc    = current ? current->callDescriptor() : 0;
577 
578 	if (desc && desc->poa() && desc->poa()->acceptBiDirectional()) {
579 	  const char* sendfrom = g.connection->peeraddress();
580 	  omniIOR::add_TAG_OMNIORB_BIDIR(sendfrom, *ior);
581 	}
582       }
583     }
584     omniObjRef* objref = omniPy::createObjRef(repoId,ior,0);
585 
586     if (!objref) OMNIORB_THROW(MARSHAL, MARSHAL_InvalidIOR,
587 			       (CORBA::CompletionStatus)s.completion());
588     return
589       (CORBA::Object_ptr)objref->_ptrToObjRef(CORBA::Object::_PD_repoId);
590   }
591   return 0; // To shut GCC up
592 }
593 
594 
595 //
596 // Python objref type
597 
598 extern "C" {
599 
600   static void
pyObjRef_dealloc(PyObjRefObject * self)601   pyObjRef_dealloc(PyObjRefObject* self)
602   {
603     {
604       omniPy::InterpreterUnlocker _u;
605       CORBA::release(self->obj);
606     }
607     Py_TYPE(self)->tp_free((PyObject*)self);
608   }
609 
610   static PyObject*
pyObjRef_invoke(PyObjRefObject * self,PyObject * args)611   pyObjRef_invoke(PyObjRefObject* self, PyObject* args)
612   {
613     // Arg format
614     //  (op_name, (in_desc,out_desc,exc_desc [, ctxt [,values]]), args)
615     //
616     //  exc_desc is a dictionary containing a mapping from repoIds to
617     //  exception descriptor tuples.
618 
619     omniPy::Py_omniCallDescriptor::InvokeArgs iargs(self->obj, args);
620     if (iargs.error())
621       return 0;
622 
623     omniPy::Py_omniCallDescriptor call_desc(iargs);
624     try {
625       {
626         omniPy::CDInterpreterUnlocker ul(call_desc);
627         iargs.oobjref->_invoke(call_desc);
628       }
629       if (!call_desc.is_oneway()) {
630 	return call_desc.result();
631       }
632       else {
633 	Py_INCREF(Py_None);
634 	return Py_None;
635       }
636     }
637     OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
638 
639     catch (omniPy::PyUserException& ex) {
640       ex.setPyExceptionState();
641     }
642     catch (...) {
643       omniORB::logs(1, "Unexpected C++ exception during Python invocation.");
644       throw;
645     }
646     return 0;
647   }
648 
649   static PyObject*
pyObjRef_invoke_sendp(PyObjRefObject * self,PyObject * args)650   pyObjRef_invoke_sendp(PyObjRefObject* self, PyObject* args)
651   {
652     // Arg format
653     //  (op_name, descriptors, args, excep name)
654 
655     omniPy::Py_omniCallDescriptor::InvokeArgs iargs(self->obj, args);
656     if (iargs.error())
657       return 0;
658 
659     omniPy::Py_omniCallDescriptor* call_desc =
660       new omniPy::Py_omniCallDescriptor(iargs, 1);
661 
662     iargs.oobjref->_invoke_async(call_desc);
663 
664     return call_desc->poller();
665   }
666 
667 
668   static PyObject*
pyObjRef_invoke_sendc(PyObjRefObject * self,PyObject * args)669   pyObjRef_invoke_sendc(PyObjRefObject* self, PyObject* args)
670   {
671     // Arg format
672     //  (op_name, descriptors, args, excep name, callback)
673 
674     omniPy::Py_omniCallDescriptor::InvokeArgs iargs(self->obj, args);
675     if (iargs.error())
676       return 0;
677 
678     omniPy::Py_omniCallDescriptor* call_desc =
679       new omniPy::Py_omniCallDescriptor(iargs, 0);
680 
681     iargs.oobjref->_invoke_async(call_desc);
682 
683     Py_INCREF(Py_None);
684     return Py_None;
685   }
686 
687 
688   static PyObject*
pyObjRef_isA(PyObjRefObject * self,PyObject * args)689   pyObjRef_isA(PyObjRefObject* self, PyObject* args)
690   {
691     char* repoId;
692 
693     if (!PyArg_ParseTuple(args, (char*)"s", &repoId))
694       return 0;
695 
696     CORBA::Boolean isa;
697 
698     try {
699       omniPy::InterpreterUnlocker ul;
700       isa = self->obj->_is_a(repoId);
701     }
702     OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
703 
704     return PyBool_FromLong(isa);
705   }
706 
707   static PyObject*
pyObjRef_nonExistent(PyObjRefObject * self,PyObject * args)708   pyObjRef_nonExistent(PyObjRefObject* self, PyObject* args)
709   {
710     CORBA::Boolean nex;
711 
712     try {
713       omniPy::InterpreterUnlocker ul;
714       nex = self->obj->_non_existent();
715     }
716     OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
717 
718     return PyBool_FromLong(nex);
719   }
720 
721   static PyObject*
pyObjRef_isEquivalent(PyObjRefObject * self,PyObject * args)722   pyObjRef_isEquivalent(PyObjRefObject* self, PyObject* args)
723   {
724     PyObject* pyobjref2;
725 
726     if (!PyArg_ParseTuple(args, (char*)"O", &pyobjref2))
727       return 0;
728 
729     CORBA::Object_ptr cxxobjref = omniPy::getObjRef(pyobjref2);
730     RAISE_PY_BAD_PARAM_IF(!cxxobjref, BAD_PARAM_WrongPythonType);
731 
732     CORBA::Boolean ise;
733 
734     try {
735       omniPy::InterpreterUnlocker ul;
736       ise = self->obj->_is_equivalent(cxxobjref);
737     }
738     OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
739 
740     return PyBool_FromLong(ise);
741   }
742 
743   static PyObject*
pyObjRef_hash(PyObjRefObject * self,PyObject * args)744   pyObjRef_hash(PyObjRefObject* self, PyObject* args)
745   {
746     CORBA::ULong max;
747 
748     if (!PyArg_ParseTuple(args, (char*)"i", &max))
749       return 0;
750 
751     CORBA::ULong h = self->obj->_hash(max);
752     return Int_FromLong(h);
753   }
754 
755 
756   static PyObject*
pyObjRef_narrow(PyObjRefObject * self,PyObject * args)757   pyObjRef_narrow(PyObjRefObject* self, PyObject* args)
758   {
759     char* repoId;
760     int   checked;
761 
762     if (!PyArg_ParseTuple(args, (char*)"si", &repoId, &checked))
763       return 0;
764 
765     CORBA::Boolean    isa;
766     CORBA::Object_ptr cxxdest = 0;
767 
768     try {
769       omniPy::InterpreterUnlocker ul;
770 
771       if (checked || self->obj->_NP_is_pseudo())
772 	isa = self->obj->_is_a(repoId);
773       else
774 	isa = 1;
775 
776       if (isa) {
777 	if (!self->obj->_NP_is_pseudo()) {
778 	  omniObjRef* oosource = self->obj->_PR_getobj();
779 	  omniObjRef* oodest;
780 	  {
781 	    omni_tracedmutex_lock sync(*omni::internalLock);
782 	    oodest = omniPy::createObjRef(repoId, oosource->_getIOR(), 1,
783 					  oosource->_identity(), 1,
784 					  oosource->_isForwardLocation());
785 	  }
786 	  cxxdest = (CORBA::Object_ptr)
787 	                   (oodest->_ptrToObjRef(CORBA::Object::_PD_repoId));
788 	}
789 	else
790 	  cxxdest = CORBA::Object::_duplicate(self->obj);
791       }
792     }
793     OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
794 
795     if (isa) {
796       return omniPy::createPyCorbaObjRef(repoId, cxxdest);
797     }
798     else {
799       Py_INCREF(Py_None);
800       return Py_None;
801     }
802   }
803 
804   static PyObject*
pyObjRef_disconnect(PyObjRefObject * self,PyObject * args)805   pyObjRef_disconnect(PyObjRefObject* self, PyObject* args)
806   {
807     try {
808       omniObjRef* oo = self->obj->_PR_getobj();
809       if (oo)
810         oo->_NP_disconnect();
811     }
812     OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
813 
814     Py_INCREF(Py_None);
815     return Py_None;
816   }
817 
818   static PyMethodDef pyObjRef_methods[] = {
819     {(char*)"invoke",
820      (PyCFunction)pyObjRef_invoke,
821      METH_VARARGS},
822 
823     {(char*)"invoke_sendp",
824      (PyCFunction)pyObjRef_invoke_sendp,
825      METH_VARARGS},
826 
827     {(char*)"invoke_sendc",
828      (PyCFunction)pyObjRef_invoke_sendc,
829      METH_VARARGS},
830 
831     {(char*)"isA",
832      (PyCFunction)pyObjRef_isA,
833      METH_VARARGS},
834 
835     {(char*)"nonExistent",
836      (PyCFunction)pyObjRef_nonExistent,
837      METH_NOARGS},
838 
839     {(char*)"isEquivalent",
840      (PyCFunction)pyObjRef_isEquivalent,
841      METH_VARARGS},
842 
843     {(char*)"hash",
844      (PyCFunction)pyObjRef_hash,
845      METH_VARARGS},
846 
847     {(char*)"narrow",
848      (PyCFunction)pyObjRef_narrow,
849      METH_VARARGS},
850 
851     {(char*)"disconnect",
852      (PyCFunction)pyObjRef_disconnect,
853      METH_NOARGS},
854 
855     {NULL,NULL}
856   };
857 
858   static PyTypeObject pyObjRefType = {
859     PyVarObject_HEAD_INIT(0,0)
860     (char*)"_omnipy.PyObjRefObject",   /* tp_name */
861     sizeof(PyObjRefObject),            /* tp_basicsize */
862     0,                                 /* tp_itemsize */
863     (destructor)pyObjRef_dealloc,      /* tp_dealloc */
864     0,                                 /* tp_print */
865     0,                                 /* tp_getattr */
866     0,                                 /* tp_setattr */
867     0,                                 /* tp_compare */
868     0,                                 /* tp_repr */
869     0,                                 /* tp_as_number */
870     0,                                 /* tp_as_sequence */
871     0,                                 /* tp_as_mapping */
872     0,                                 /* tp_hash  */
873     0,                                 /* tp_call */
874     0,                                 /* tp_str */
875     0,                                 /* tp_getattro */
876     0,                                 /* tp_setattro */
877     0,                                 /* tp_as_buffer */
878     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
879     (char*)"Internal ObjRef object",   /* tp_doc */
880     0,                                 /* tp_traverse */
881     0,                                 /* tp_clear */
882     0,                                 /* tp_richcompare */
883     0,                                 /* tp_weaklistoffset */
884     0,                                 /* tp_iter */
885     0,                                 /* tp_iternext */
886     pyObjRef_methods,                  /* tp_methods */
887   };
888 };
889 
890 
891 PyObject*
createPyObjRefObject(CORBA::Object_ptr obj)892 omniPy::createPyObjRefObject(CORBA::Object_ptr obj)
893 {
894   PyObjRefObject* self = PyObject_New(PyObjRefObject, &pyObjRefType);
895   self->obj = obj;
896   return (PyObject*)self;
897 }
898 
899 CORBA::Boolean
pyObjRefCheck(PyObject * pyobj)900 omniPy::pyObjRefCheck(PyObject* pyobj)
901 {
902   return PyObject_TypeCheck(pyobj, &pyObjRefType);
903 }
904 
905 PyTypeObject* omniPy::PyObjRefType;
906 
907 void
initObjRefFunc(PyObject * d)908 omniPy::initObjRefFunc(PyObject* d)
909 {
910   int r = PyType_Ready(&pyObjRefType);
911   OMNIORB_ASSERT(r == 0);
912 
913   omniPy::PyObjRefType = &pyObjRefType;
914 }
915