summaryrefslogtreecommitdiff
path: root/python/modules/IcePy/ValueFactoryManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'python/modules/IcePy/ValueFactoryManager.cpp')
-rw-r--r--python/modules/IcePy/ValueFactoryManager.cpp536
1 files changed, 536 insertions, 0 deletions
diff --git a/python/modules/IcePy/ValueFactoryManager.cpp b/python/modules/IcePy/ValueFactoryManager.cpp
new file mode 100644
index 00000000000..b3e2bd43513
--- /dev/null
+++ b/python/modules/IcePy/ValueFactoryManager.cpp
@@ -0,0 +1,536 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#ifdef _WIN32
+# include <IceUtil/Config.h>
+#endif
+#include <ValueFactoryManager.h>
+#include <Thread.h>
+#include <Types.h>
+#include <Ice/LocalException.h>
+
+using namespace std;
+using namespace IcePy;
+
+namespace IcePy
+{
+
+struct ValueFactoryManagerObject
+{
+ PyObject_HEAD
+ ValueFactoryManagerPtr* vfm;
+};
+
+}
+
+namespace
+{
+
+ClassInfoPtr
+getClassInfo(const string& id)
+{
+ ClassInfoPtr info;
+
+ if(id == Ice::Object::ice_staticId())
+ {
+ //
+ // When the ID is that of Ice::Object, it indicates that the stream has not
+ // found a factory and is providing us an opportunity to preserve the object.
+ //
+ info = lookupClassInfo("::Ice::UnknownSlicedObject");
+ }
+ else
+ {
+ info = lookupClassInfo(id);
+ }
+
+ return info;
+}
+
+}
+
+IcePy::ValueFactoryManager::ValueFactoryManager()
+{
+ //
+ // Create a Python wrapper around this object. Note that this is cyclic - we clear the
+ // reference in destroy().
+ //
+ ValueFactoryManagerObject* obj = reinterpret_cast<ValueFactoryManagerObject*>(
+ ValueFactoryManagerType.tp_alloc(&ValueFactoryManagerType, 0));
+ assert(obj);
+ obj->vfm = new ValueFactoryManagerPtr(this);
+ _self = reinterpret_cast<PyObject*>(obj);
+
+ _defaultFactory = new DefaultValueFactory;
+}
+
+IcePy::ValueFactoryManager::~ValueFactoryManager()
+{
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+ Py_XDECREF(_self);
+}
+
+void
+IcePy::ValueFactoryManager::add(const Ice::ValueFactoryPtr& f, const string& id)
+{
+ Lock lock(*this);
+
+ if(id.empty())
+ {
+ if(_defaultFactory->getDelegate())
+ {
+ throw Ice::AlreadyRegisteredException(__FILE__, __LINE__, "value factory", id);
+ }
+
+ _defaultFactory->setDelegate(f);
+ }
+ else
+ {
+ FactoryMap::iterator p = _factories.find(id);
+ if(p != _factories.end())
+ {
+ throw Ice::AlreadyRegisteredException(__FILE__, __LINE__, "value factory", id);
+ }
+
+ _factories.insert(FactoryMap::value_type(id, f));
+ }
+}
+
+Ice::ValueFactoryPtr
+IcePy::ValueFactoryManager::find(const string& id) const
+{
+ Lock lock(*this);
+
+ if(id.empty())
+ {
+ return _defaultFactory;
+ }
+
+ FactoryMap::const_iterator p = _factories.find(id);
+ if(p != _factories.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+void
+IcePy::ValueFactoryManager::add(PyObject* valueFactory, PyObject* objectFactory, const string& id)
+{
+ try
+ {
+ add(new FactoryWrapper(valueFactory, objectFactory), id);
+ }
+ catch(const Ice::Exception& ex)
+ {
+ setPythonException(ex);
+ }
+}
+
+PyObject*
+IcePy::ValueFactoryManager::findValueFactory(const string& id) const
+{
+ Ice::ValueFactoryPtr f = find(id);
+ if(f)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(f);
+ if(w)
+ {
+ return w->getValueFactory();
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject*
+IcePy::ValueFactoryManager::findObjectFactory(const string& id) const
+{
+ Ice::ValueFactoryPtr f = find(id);
+ if(f)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(f);
+ if(w)
+ {
+ return w->getObjectFactory();
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject*
+IcePy::ValueFactoryManager::getObject() const
+{
+ Py_INCREF(_self);
+ return _self;
+}
+
+void
+IcePy::ValueFactoryManager::destroy()
+{
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+
+ FactoryMap factories;
+
+ {
+ Lock lock(*this);
+
+ //
+ // Break the cyclic reference.
+ //
+ Py_DECREF(_self);
+ _self = 0;
+
+ factories.swap(_factories);
+ }
+
+ for(FactoryMap::iterator p = factories.begin(); p != factories.end(); ++p)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(p->second);
+ if(w)
+ {
+ w->destroy();
+ }
+ }
+
+ _defaultFactory->destroy();
+}
+
+IcePy::FactoryWrapper::FactoryWrapper(PyObject* valueFactory, PyObject* objectFactory) :
+ _valueFactory(valueFactory),
+ _objectFactory(objectFactory)
+{
+ Py_INCREF(_valueFactory);
+ Py_INCREF(_objectFactory);
+ assert(_valueFactory != Py_None); // This should always be present.
+}
+
+IcePy::FactoryWrapper::~FactoryWrapper()
+{
+ Py_DECREF(_valueFactory);
+ Py_DECREF(_objectFactory);
+}
+
+Ice::ValuePtr
+IcePy::FactoryWrapper::create(const string& id)
+{
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+
+ //
+ // Get the type information.
+ //
+ ClassInfoPtr info = getClassInfo(id);
+
+ if(!info)
+ {
+ return 0;
+ }
+
+ PyObjectHandle obj = PyObject_CallFunction(_valueFactory, STRCAST("s"), id.c_str());
+
+ if(!obj.get())
+ {
+ assert(PyErr_Occurred());
+ throw AbortMarshaling();
+ }
+
+ if(obj.get() == Py_None)
+ {
+ return 0;
+ }
+
+ return new ObjectReader(obj.get(), info);
+}
+
+PyObject*
+IcePy::FactoryWrapper::getValueFactory() const
+{
+ Py_INCREF(_valueFactory);
+ return _valueFactory;
+}
+
+PyObject*
+IcePy::FactoryWrapper::getObjectFactory() const
+{
+ Py_INCREF(_objectFactory);
+ return _objectFactory;
+}
+
+void
+IcePy::FactoryWrapper::destroy()
+{
+ if(_objectFactory != Py_None)
+ {
+ PyObjectHandle obj = PyObject_CallMethod(_objectFactory, STRCAST("destroy"), 0);
+ PyErr_Clear(); // Ignore errors.
+ }
+}
+
+Ice::ValuePtr
+IcePy::DefaultValueFactory::create(const string& id)
+{
+ AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
+
+ Ice::ValuePtr v;
+
+ //
+ // Give the application-provided default factory a chance to create the object first.
+ //
+ if(_delegate)
+ {
+ v = _delegate->create(id);
+ if(v)
+ {
+ return v;
+ }
+ }
+
+ //
+ // Get the type information.
+ //
+ ClassInfoPtr info = getClassInfo(id);
+
+ if(!info)
+ {
+ return 0;
+ }
+
+ //
+ // If the requested type is an abstract class, then we give up.
+ //
+ if(info->isAbstract)
+ {
+ return 0;
+ }
+
+ //
+ // Instantiate the object.
+ //
+ PyTypeObject* type = reinterpret_cast<PyTypeObject*>(info->pythonType.get());
+ PyObjectHandle args = PyTuple_New(0);
+ PyObjectHandle obj = type->tp_new(type, args.get(), 0);
+ if(!obj.get())
+ {
+ assert(PyErr_Occurred());
+ throw AbortMarshaling();
+ }
+
+ return new ObjectReader(obj.get(), info);
+}
+
+void
+IcePy::DefaultValueFactory::setDelegate(const Ice::ValueFactoryPtr& d)
+{
+ _delegate = d;
+}
+
+PyObject*
+IcePy::DefaultValueFactory::getValueFactory() const
+{
+ if(_delegate)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
+ if(w)
+ {
+ return w->getValueFactory();
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject*
+IcePy::DefaultValueFactory::getObjectFactory() const
+{
+ if(_delegate)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
+ if(w)
+ {
+ return w->getObjectFactory();
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+void
+IcePy::DefaultValueFactory::destroy()
+{
+ if(_delegate)
+ {
+ FactoryWrapperPtr w = FactoryWrapperPtr::dynamicCast(_delegate);
+ if(w)
+ {
+ w->destroy();
+ }
+ }
+
+ _delegate = 0;
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static ValueFactoryManagerObject*
+valueFactoryManagerNew(PyTypeObject* /*type*/, PyObject* /*args*/, PyObject* /*kwds*/)
+{
+ PyErr_Format(PyExc_RuntimeError, STRCAST("Do not instantiate this object directly"));
+ return 0;
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static void
+valueFactoryManagerDealloc(ValueFactoryManagerObject* self)
+{
+ delete self->vfm;
+ Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static PyObject*
+valueFactoryManagerAdd(ValueFactoryManagerObject* self, PyObject* args)
+{
+ assert(self->vfm);
+
+ PyObject* factoryType = lookupType("types.FunctionType");
+ assert(factoryType);
+
+ PyObject* factory;
+ PyObject* idObj;
+ if(!PyArg_ParseTuple(args, STRCAST("O!O"), factoryType, &factory, &idObj))
+ {
+ return 0;
+ }
+
+ string id;
+ if(!getStringArg(idObj, "id", id))
+ {
+ return 0;
+ }
+
+ (*self->vfm)->add(factory, Py_None, id);
+ if(PyErr_Occurred())
+ {
+ return 0;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#ifdef WIN32
+extern "C"
+#endif
+static PyObject*
+valueFactoryManagerFind(ValueFactoryManagerObject* self, PyObject* args)
+{
+ assert(self->vfm);
+
+ PyObject* idObj;
+ if(!PyArg_ParseTuple(args, STRCAST("O"), &idObj))
+ {
+ return 0;
+ }
+
+ string id;
+ if(!getStringArg(idObj, "id", id))
+ {
+ return 0;
+ }
+
+ return (*self->vfm)->findValueFactory(id);
+}
+
+static PyMethodDef ValueFactoryManagerMethods[] =
+{
+ { STRCAST("add"), reinterpret_cast<PyCFunction>(valueFactoryManagerAdd), METH_VARARGS,
+ PyDoc_STR(STRCAST("add(factory, id) -> None")) },
+ { STRCAST("find"), reinterpret_cast<PyCFunction>(valueFactoryManagerFind), METH_VARARGS,
+ PyDoc_STR(STRCAST("find(id) -> function")) },
+ { 0, 0 } /* sentinel */
+};
+
+namespace IcePy
+{
+
+PyTypeObject ValueFactoryManagerType =
+{
+ /* The ob_type field must be initialized in the module init function
+ * to be portable to Windows without using C++. */
+ PyVarObject_HEAD_INIT(0, 0)
+ STRCAST("IcePy.ValueFactoryManager"), /* tp_name */
+ sizeof(ValueFactoryManagerObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ reinterpret_cast<destructor>(valueFactoryManagerDealloc), /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ ValueFactoryManagerMethods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ reinterpret_cast<newfunc>(valueFactoryManagerNew), /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+};
+
+}
+
+bool
+IcePy::initValueFactoryManager(PyObject* module)
+{
+ if(PyType_Ready(&ValueFactoryManagerType) < 0)
+ {
+ return false;
+ }
+ PyTypeObject* type = &ValueFactoryManagerType; // Necessary to prevent GCC's strict-alias warnings.
+ if(PyModule_AddObject(module, STRCAST("ValueFactoryManager"), reinterpret_cast<PyObject*>(type)) < 0)
+ {
+ return false;
+ }
+
+ return true;
+}