diff options
Diffstat (limited to 'py/modules/IcePy/ObjectAdapter.cpp')
-rw-r--r-- | py/modules/IcePy/ObjectAdapter.cpp | 330 |
1 files changed, 29 insertions, 301 deletions
diff --git a/py/modules/IcePy/ObjectAdapter.cpp b/py/modules/IcePy/ObjectAdapter.cpp index b00e1ea1640..140202ab113 100644 --- a/py/modules/IcePy/ObjectAdapter.cpp +++ b/py/modules/IcePy/ObjectAdapter.cpp @@ -11,16 +11,13 @@ #include <Communicator.h> #include <Current.h> #include <Identity.h> -#include <Marshal.h> +#include <Operation.h> #include <Proxy.h> -#include <Types.h> #include <Util.h> #include <Ice/Communicator.h> -#include <Ice/Initialize.h> #include <Ice/LocalException.h> #include <Ice/ObjectAdapter.h> #include <Ice/ServantLocator.h> -#include <Ice/Stream.h> using namespace std; using namespace IcePy; @@ -35,27 +32,6 @@ struct ObjectAdapterObject }; // -// Dispatches a user-defined operation. -// -class Dispatcher : public IceUtil::Shared -{ -public: - - Dispatcher(const OperationInfoPtr&); - ~Dispatcher(); - - bool dispatch(PyObject*, const vector<Ice::Byte>&, vector<Ice::Byte>&, const Ice::Current&); - -private: - - OperationInfoPtr _info; - MarshalerPtr _resultMarshaler; - vector<MarshalerPtr> _inParams; - vector<MarshalerPtr> _outParams; -}; -typedef IceUtil::Handle<Dispatcher> DispatcherPtr; - -// // Encapsulates a Python servant. // class ServantWrapper : public Ice::Blobject @@ -72,9 +48,10 @@ public: private: PyObject* _servant; - ClassInfoPtr _info; - typedef map<string, DispatcherPtr> DispatcherMap; - DispatcherMap _dispatcherMap; + string _id; + typedef map<string, OperationPtr> OperationMap; + OperationMap _operationMap; + OperationMap::iterator _lastOp; }; typedef IceUtil::Handle<ServantWrapper> ServantWrapperPtr; @@ -119,242 +96,8 @@ typedef IceUtil::Handle<ServantLocatorWrapper> ServantLocatorWrapperPtr; } -IcePy::Dispatcher::Dispatcher(const OperationInfoPtr& info) : - _info(info) -{ - if(_info->returnType) - { - _resultMarshaler = Marshaler::createMarshaler(_info->returnType); - } - - TypeInfoList::iterator p; - - for(p = _info->inParams.begin(); p != _info->inParams.end(); ++p) - { - MarshalerPtr marshaler = Marshaler::createMarshaler(*p); - assert(marshaler); - _inParams.push_back(marshaler); - } - - for(p = _info->outParams.begin(); p != _info->outParams.end(); ++p) - { - MarshalerPtr marshaler = Marshaler::createMarshaler(*p); - assert(marshaler); - _outParams.push_back(marshaler); - } -} - -IcePy::Dispatcher::~Dispatcher() -{ -} - -bool -IcePy::Dispatcher::dispatch(PyObject* servant, const vector<Ice::Byte>& inParams, vector<Ice::Byte>& outParams, - const Ice::Current& current) -{ - string fixedName = fixIdent(_info->name); - Ice::CommunicatorPtr communicator = current.adapter->getCommunicator(); - - // - // Unmarshal the in parameters. - // - PyObjectHandle inArgs = PyTuple_New(static_cast<int>(_inParams.size()) + 1); // Leave room for Ice.Current. - if(inArgs.get() == NULL) - { - return false; - } - - Ice::InputStreamPtr is = Ice::createInputStream(communicator, inParams); - int i = 0; - try - { - for(vector<MarshalerPtr>::iterator p = _inParams.begin(); p != _inParams.end(); ++p, ++i) - { - ObjectMarshalerPtr om = ObjectMarshalerPtr::dynamicCast(*p); - if(om) - { - om->unmarshalObject(communicator, is, new TupleReceiver(om->info(), inArgs.get(), i)); - } - else - { - PyObjectHandle arg = (*p)->unmarshal(communicator, is); - if(arg.get() == NULL) - { - return false; - } - if(PyTuple_SET_ITEM(inArgs.get(), i, arg.get()) < 0) - { - return false; - } - arg.release(); // PyTuple_SET_ITEM steals a reference. - } - } - is->finished(); - } - catch(const AbortMarshaling&) - { - throwPythonException(); - } - - // - // Create an object to represent Ice::Current. We need to append this to the argument tuple. - // - PyObjectHandle curr = createCurrent(current); - if(PyTuple_SET_ITEM(inArgs.get(), static_cast<int>(_inParams.size()), curr.get()) < 0) - { - return false; - } - curr.release(); // PyTuple_SET_ITEM steals a reference. - - // - // Dispatch the operation. Use fixedName here, not _info->name. - // - PyObjectHandle method = PyObject_GetAttrString(servant, const_cast<char*>(fixedName.c_str())); - if(method.get() == NULL) - { - PyErr_SetString(PyExc_AttributeError, const_cast<char*>(fixedName.c_str())); - return false; - } - - PyObjectHandle result = PyObject_Call(method.get(), inArgs.get(), NULL); - - Ice::OutputStreamPtr os = Ice::createOutputStream(communicator); - - // - // Check for exceptions. - // - PyObject* exType = PyErr_Occurred(); - if(exType) - { - // - // A servant that calls sys.exit() will raise the SystemExit exception. - // This is normally caught by the interpreter, causing it to exit. - // However, we have no way to pass this exception to the interpreter, - // so we act on it directly. - // - if(PyErr_GivenExceptionMatches(exType, PyExc_SystemExit)) - { - handleSystemExit(); // Does not return. - } - - PyObjectHandle ex = getPythonException(); // Retrieve it before another Python API call clears it. - - PyObject* userExceptionType = lookupType("Ice.UserException"); - - if(PyErr_GivenExceptionMatches(exType, userExceptionType)) - { - // - // Get the exception's id and Verify that it is legal to be thrown from the operation. - // - PyObjectHandle id = PyObject_CallMethod(ex.get(), "ice_id", NULL); - PyErr_Clear(); - if(id.get() == NULL || !_info->validateException(ex.get())) - { - throwPythonException(ex.get()); - } - else - { - assert(PyString_Check(id.get())); - char* str = PyString_AS_STRING(id.get()); - ExceptionInfoPtr info = getExceptionInfo(str); - if(!info) - { - Ice::UnknownUserException e(__FILE__, __LINE__); - e.unknown = PyString_AS_STRING(id.get()); - throw e; - } - - try - { - MarshalerPtr marshaler = Marshaler::createExceptionMarshaler(info); - assert(marshaler); - - ObjectMap objectMap; - marshaler->marshal(ex.get(), os, &objectMap); - os->finished(outParams); - } - catch(const AbortMarshaling&) - { - throwPythonException(); - } - } - } - else - { - throwPythonException(ex.get()); - } - - return false; - } - - if(_outParams.size() > 0 || _resultMarshaler) - { - try - { - // - // Unmarshal the results. If there is more than one value to be returned, then they must be - // returned in a tuple of the form (result, outParam1, ...). - // - - i = _resultMarshaler ? 1 : 0; - int numResults = _outParams.size() + i; - if(numResults > 1) - { - if(!PyTuple_Check(result.get()) || PyTuple_GET_SIZE(result.get()) != numResults) - { - ostringstream ostr; - ostr << "operation `" << fixedName << "' should return a tuple of length " << numResults; - string str = ostr.str(); - PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str())); - throw Ice::MarshalException(__FILE__, __LINE__); - } - } - - ObjectMap objectMap; - for(vector<MarshalerPtr>::iterator q = _outParams.begin(); q != _outParams.end(); ++q, ++i) - { - PyObject* arg; - if(numResults > 1) - { - arg = PyTuple_GET_ITEM(result.get(), i); - } - else - { - arg = result.get(); - assert(_outParams.size() == 1); - } - - (*q)->marshal(arg, os, &objectMap); - } - - if(_resultMarshaler) - { - PyObject* res; - if(numResults > 1) - { - res = PyTuple_GET_ITEM(result.get(), 0); - } - else - { - assert(_outParams.size() == 0); - res = result.get(); - } - _resultMarshaler->marshal(res, os, &objectMap); - } - - os->finished(outParams); - } - catch(const AbortMarshaling&) - { - throwPythonException(); - } - } - - return true; -} - IcePy::ServantWrapper::ServantWrapper(PyObject* servant) : - _servant(servant) + _servant(servant), _lastOp(_operationMap.end()) { Py_INCREF(_servant); PyObjectHandle id = PyObject_CallMethod(servant, "ice_id", NULL); @@ -366,17 +109,7 @@ IcePy::ServantWrapper::ServantWrapper(PyObject* servant) : } else { - char* s = PyString_AS_STRING(id.get()); - TypeInfoPtr info = getTypeInfo(s); - _info = ClassInfoPtr::dynamicCast(info); - if(!info) - { - PyErr_Format(PyExc_RuntimeError, "unknown type id `%s'", s); - } - else if(!_info) - { - PyErr_Format(PyExc_RuntimeError, "type id `%s' is not a class", s); - } + _id = PyString_AS_STRING(id.get()); } } } @@ -392,40 +125,35 @@ IcePy::ServantWrapper::ice_invoke(const vector<Ice::Byte>& inParams, vector<Ice: { AdoptThread adoptThread; // Ensure the current thread is able to call into Python. - DispatcherMap::iterator p = _dispatcherMap.find(current.operation); - DispatcherPtr dispatcher; - if(p == _dispatcherMap.end()) + OperationPtr op; + if(_lastOp != _operationMap.end() && _lastOp->first == current.operation) { - OperationInfoPtr op = _info->findOperation(current.operation); - - if(!op) + op = _lastOp->second; + } + else + { + _lastOp = _operationMap.find(current.operation); + if(_lastOp == _operationMap.end()) { - // - // Look for the operation in the description of Ice.Object. - // - ClassInfoPtr info = ClassInfoPtr::dynamicCast(getTypeInfo("::Ice::Object")); - assert(info); - op = info->findOperation(current.operation); - } + op = getOperation(_id, current.operation); + if(!op) + { + Ice::OperationNotExistException ex(__FILE__, __LINE__); + ex.id = current.id; + ex.facet = current.facet; + ex.operation = current.operation; + throw ex; + } - if(!op) + _lastOp = _operationMap.insert(OperationMap::value_type(current.operation, op)).first; + } + else { - Ice::OperationNotExistException ex(__FILE__, __LINE__); - ex.id = current.id; - ex.facet = current.facet; - ex.operation = current.operation; - throw ex; + op = _lastOp->second; } - - dispatcher = new Dispatcher(op); - _dispatcherMap.insert(DispatcherMap::value_type(current.operation, dispatcher)); - } - else - { - dispatcher = p->second; } - return dispatcher->dispatch(_servant, inParams, outParams, current); + return op->dispatch(_servant, inParams, outParams, current); } PyObject* |