diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/modules/IcePy/Communicator.cpp | 86 | ||||
-rw-r--r-- | python/modules/IcePy/Makefile.mak | 1 | ||||
-rw-r--r-- | python/modules/IcePy/ObjectFactory.cpp | 73 | ||||
-rw-r--r-- | python/modules/IcePy/ObjectFactory.h | 11 | ||||
-rw-r--r-- | python/modules/IcePy/Util.cpp | 2 | ||||
-rw-r--r-- | python/python/Ice.py | 7 | ||||
-rw-r--r-- | python/python/Makefile | 1 | ||||
-rw-r--r-- | python/python/Makefile.mak | 7 | ||||
-rw-r--r-- | python/test/Ice/exceptions/AllTests.py | 11 | ||||
-rw-r--r-- | python/test/Ice/objects/AllTests.py | 57 | ||||
-rwxr-xr-x | python/test/Ice/objects/Server.py | 14 | ||||
-rw-r--r-- | python/test/Ice/slicing/objects/AllTests.py | 24 |
12 files changed, 212 insertions, 82 deletions
diff --git a/python/modules/IcePy/Communicator.cpp b/python/modules/IcePy/Communicator.cpp index 919086d9ae8..df7d2282927 100644 --- a/python/modules/IcePy/Communicator.cpp +++ b/python/modules/IcePy/Communicator.cpp @@ -24,6 +24,7 @@ #include <Thread.h> #include <Types.h> #include <Util.h> +#include <Ice/ValueFactory.h> #include <Ice/Initialize.h> #include <Ice/CommunicatorAsync.h> #include <Ice/LocalException.h> @@ -1197,7 +1198,51 @@ communicatorAddObjectFactory(CommunicatorObject* self, PyObject* args) } - if(!pof->add(factory, id)) + if(!pof->addObjectFactory(factory, id)) + { + return 0; + } + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef WIN32 +extern "C" +#endif +static PyObject* +communicatorAddValueFactory(CommunicatorObject* self, PyObject* args) +{ + PyObject* factoryType = lookupType("Ice.ValueFactory"); + assert(factoryType); + + PyObject* factory; + PyObject* strObj; + if(!PyArg_ParseTuple(args, STRCAST("O!O"), factoryType, &factory, &strObj)) + { + return 0; + } + + string id; + if(!getStringArg(strObj, "id", id)) + { + return 0; + } + + ObjectFactoryPtr pof; + try + { + pof = ObjectFactoryPtr::dynamicCast((*self->communicator)->findObjectFactory("")); + assert(pof); + } + catch(const Ice::Exception& ex) + { + setPythonException(ex); + return 0; + + } + + if(!pof->addValueFactory(factory, id)) { return 0; } @@ -1236,7 +1281,40 @@ communicatorFindObjectFactory(CommunicatorObject* self, PyObject* args) return 0; } - return pof->find(id); + return pof->findObjectFactory(id); +} + +#ifdef WIN32 +extern "C" +#endif +static PyObject* +communicatorFindValueFactory(CommunicatorObject* self, PyObject* args) +{ + PyObject* strObj; + if(!PyArg_ParseTuple(args, STRCAST("O"), &strObj)) + { + return 0; + } + + string id; + if(!getStringArg(strObj, "id", id)) + { + return 0; + } + + ObjectFactoryPtr pof; + try + { + pof = ObjectFactoryPtr::dynamicCast((*self->communicator)->findObjectFactory("")); + assert(pof); + } + catch(const Ice::Exception& ex) + { + setPythonException(ex); + return 0; + } + + return pof->findValueFactory(id); } #ifdef WIN32 @@ -1570,6 +1648,10 @@ static PyMethodDef CommunicatorMethods[] = PyDoc_STR(STRCAST("addObjectFactory(factory, id) -> None")) }, { STRCAST("findObjectFactory"), reinterpret_cast<PyCFunction>(communicatorFindObjectFactory), METH_VARARGS, PyDoc_STR(STRCAST("findObjectFactory(id) -> Ice.ObjectFactory")) }, + { STRCAST("addValueFactory"), reinterpret_cast<PyCFunction>(communicatorAddValueFactory), METH_VARARGS, + PyDoc_STR(STRCAST("addValueFactory(factory, id) -> None")) }, + { STRCAST("findValueFactory"), reinterpret_cast<PyCFunction>(communicatorFindValueFactory), METH_VARARGS, + PyDoc_STR(STRCAST("findValueFactory(id) -> Ice.ValueFactory")) }, { STRCAST("getImplicitContext"), reinterpret_cast<PyCFunction>(communicatorGetImplicitContext), METH_NOARGS, PyDoc_STR(STRCAST("getImplicitContext() -> Ice.ImplicitContext")) }, { STRCAST("getProperties"), reinterpret_cast<PyCFunction>(communicatorGetProperties), METH_NOARGS, diff --git a/python/modules/IcePy/Makefile.mak b/python/modules/IcePy/Makefile.mak index 6ef88199500..4473a818f67 100644 --- a/python/modules/IcePy/Makefile.mak +++ b/python/modules/IcePy/Makefile.mak @@ -35,6 +35,7 @@ OBJS = .\BatchRequestInterceptor.obj \ .\Types.obj \ .\Util.obj + # # Get Make.common.rules.mak to figure out CPP_COMPILER by setting it # to "auto" diff --git a/python/modules/IcePy/ObjectFactory.cpp b/python/modules/IcePy/ObjectFactory.cpp index 1829d32956b..d3720714a29 100644 --- a/python/modules/IcePy/ObjectFactory.cpp +++ b/python/modules/IcePy/ObjectFactory.cpp @@ -25,7 +25,8 @@ IcePy::ObjectFactory::ObjectFactory() IcePy::ObjectFactory::~ObjectFactory() { - assert(_factoryMap.empty()); + assert(_valueFactoryMap.empty()); + assert(_objectFactoryMap.empty()); } Ice::ObjectPtr @@ -39,8 +40,8 @@ IcePy::ObjectFactory::create(const string& id) { Lock sync(*this); - FactoryMap::iterator p = _factoryMap.find(id); - if(p != _factoryMap.end()) + FactoryMap::iterator p = _valueFactoryMap.find(id); + if(p != _valueFactoryMap.end()) { factory = p->second; } @@ -112,12 +113,15 @@ IcePy::ObjectFactory::create(const string& id) void IcePy::ObjectFactory::destroy() { - FactoryMap factories; + FactoryMap valueFactories; + FactoryMap objectFactories; { Lock sync(*this); - factories = _factoryMap; - _factoryMap.clear(); + objectFactories = _objectFactoryMap; + valueFactories = _valueFactoryMap; + _valueFactoryMap.clear(); + _objectFactoryMap.clear(); } // @@ -126,66 +130,89 @@ IcePy::ObjectFactory::destroy() // AdoptThread adoptThread; - for(FactoryMap::iterator p = factories.begin(); p != factories.end(); ++p) + for(FactoryMap::iterator p = _objectFactoryMap.begin(); p != _objectFactoryMap.end(); ++p) { // - // Invoke the destroy method on each registered Python factory. + // Invoke the destroy method on each registered Python "object" factory. // PyObjectHandle obj = PyObject_CallMethod(p->second, STRCAST("destroy"), 0); PyErr_Clear(); // Ignore errors. Py_DECREF(p->second); } + for(FactoryMap::iterator p = _valueFactoryMap.begin(); p != _valueFactoryMap.end(); ++p) + { + PyErr_Clear(); // Ignore errors. + Py_DECREF(p->second); + } } bool -IcePy::ObjectFactory::add(PyObject* factory, const string& id) +IcePy::ObjectFactory::addValueFactory(PyObject* factory, const string& id) { Lock sync(*this); - FactoryMap::iterator p = _factoryMap.find(id); - if(p != _factoryMap.end()) + FactoryMap::iterator p = _valueFactoryMap.find(id); + if(p != _valueFactoryMap.end()) { Ice::AlreadyRegisteredException ex(__FILE__, __LINE__); - ex.kindOfObject = "object factory"; + ex.kindOfObject = "value factory"; ex.id = id; setPythonException(ex); return false; } - _factoryMap.insert(FactoryMap::value_type(id, factory)); + _valueFactoryMap.insert(FactoryMap::value_type(id, factory)); Py_INCREF(factory); return true; } bool -IcePy::ObjectFactory::remove(const string& id) +IcePy::ObjectFactory::addObjectFactory(PyObject* factory, const string& id) { Lock sync(*this); - FactoryMap::iterator p = _factoryMap.find(id); - if(p == _factoryMap.end()) + FactoryMap::iterator p = _valueFactoryMap.find(id); + if(p != _valueFactoryMap.end()) { - Ice::NotRegisteredException ex(__FILE__, __LINE__); - ex.kindOfObject = "object factory"; + Ice::AlreadyRegisteredException ex(__FILE__, __LINE__); + ex.kindOfObject = "value factory"; ex.id = id; setPythonException(ex); return false; } - Py_DECREF(p->second); - _factoryMap.erase(p); + _valueFactoryMap.insert(FactoryMap::value_type(id, factory)); + Py_INCREF(factory); + _objectFactoryMap.insert(FactoryMap::value_type(id, factory)); + Py_INCREF(factory); return true; } PyObject* -IcePy::ObjectFactory::find(const string& id) +IcePy::ObjectFactory::findValueFactory(const string& id) +{ + Lock sync(*this); + + FactoryMap::iterator p = _valueFactoryMap.find(id); + if(p == _valueFactoryMap.end()) + { + Py_INCREF(Py_None); + return Py_None; + } + + Py_INCREF(p->second); + return p->second; +} + +PyObject* +IcePy::ObjectFactory::findObjectFactory(const string& id) { Lock sync(*this); - FactoryMap::iterator p = _factoryMap.find(id); - if(p == _factoryMap.end()) + FactoryMap::iterator p = _objectFactoryMap.find(id); + if(p == _objectFactoryMap.end()) { Py_INCREF(Py_None); return Py_None; diff --git a/python/modules/IcePy/ObjectFactory.h b/python/modules/IcePy/ObjectFactory.h index 8445996b330..57b93352bdd 100644 --- a/python/modules/IcePy/ObjectFactory.h +++ b/python/modules/IcePy/ObjectFactory.h @@ -34,14 +34,17 @@ public: virtual void destroy(); - bool add(PyObject*, const std::string&); - bool remove(const std::string&); - PyObject* find(const std::string&); + bool addValueFactory(PyObject*, const std::string&); + bool addObjectFactory(PyObject*, const std::string&); + + PyObject* findValueFactory(const std::string&); + PyObject* findObjectFactory(const std::string&); private: typedef std::map<std::string, PyObject*> FactoryMap; - FactoryMap _factoryMap; + FactoryMap _valueFactoryMap; + FactoryMap _objectFactoryMap; }; typedef IceUtil::Handle<ObjectFactory> ObjectFactoryPtr; diff --git a/python/modules/IcePy/Util.cpp b/python/modules/IcePy/Util.cpp index 74869df7121..b86ddffd953 100644 --- a/python/modules/IcePy/Util.cpp +++ b/python/modules/IcePy/Util.cpp @@ -818,7 +818,7 @@ convertLocalException(const Ice::LocalException& ex, PyObject* p) m = IcePy::createEncodingVersion(e.supported); PyObject_SetAttrString(p, STRCAST("supported"), m.get()); } - catch(const Ice::NoObjectFactoryException& e) + catch(const Ice::NoValueFactoryException& e) { IcePy::PyObjectHandle m; m = IcePy::createString(e.reason); diff --git a/python/python/Ice.py b/python/python/Ice.py index feb060efa54..c111781f923 100644 --- a/python/python/Ice.py +++ b/python/python/Ice.py @@ -446,6 +446,7 @@ import Ice_Locator_ice import Ice_Logger_ice import Ice_ObjectAdapter_ice import Ice_ObjectFactory_ice +import Ice_ValueFactory_ice import Ice_Process_ice import Ice_Properties_ice import Ice_RemoteLogger_ice @@ -623,6 +624,12 @@ class CommunicatorI(Communicator): def findObjectFactory(self, id): return self._impl.findObjectFactory(id) + def addValueFactory(self, factory, id): + self._impl.addValueFactory(factory, id) + + def findValueFactory(self, id): + return self._impl.findValueFactory(id) + def getImplicitContext(self): context = self._impl.getImplicitContext() if context == None: diff --git a/python/python/Makefile b/python/python/Makefile index 81fdcd867d0..9fafeab7ada 100644 --- a/python/python/Makefile +++ b/python/python/Makefile @@ -54,6 +54,7 @@ ICE_SRCS = Ice_BuiltinSequences_ice.py \ Ice_ServantLocator_ice.py \ Ice_ServantLocatorF_ice.py \ Ice_SliceChecksumDict_ice.py \ + Ice_ValueFactory_ice.py \ Ice_Version_ice.py GLACIER2_SRCS = Glacier2_Metrics_ice.py \ diff --git a/python/python/Makefile.mak b/python/python/Makefile.mak index fb5b2358780..26d8dec616b 100644 --- a/python/python/Makefile.mak +++ b/python/python/Makefile.mak @@ -50,6 +50,7 @@ ICE_SLICES = Ice\BuiltinSequences.ice \ Ice\ServantLocator.ice \ Ice\ServantLocatorF.ice \ Ice\SliceChecksumDict.ice \ + Ice\ValueFactory.ice \ Ice\Version.ice \ ICE_SRCS = $(ICE_SLICES:.ice=_ice.py) @@ -266,6 +267,12 @@ Ice_EndpointF_ice.py: "$(slicedir)/Ice/EndpointF.ice" "$(SLICEPARSERLIB)" Ice_EndpointTypes_ice.py: "$(slicedir)/Ice/EndpointTypes.ice" "$(SLICEPARSERLIB)" "$(SLICE2PY)" $(SLICE2PYFLAGS) --prefix Ice_ --no-package "$(slicedir)/Ice/EndpointTypes.ice" +Ice_ValueFactory_ice.py: "$(slicedir)/Ice/ValueFactory.ice" "$(SLICEPARSERLIB)" + "$(SLICE2PY)" $(SLICE2PYFLAGS) --prefix Ice_ --no-package "$(slicedir)/Ice/ValueFactory.ice" + +Ice_ValueFactoryF_ice.py: "$(slicedir)/Ice/ValueFactoryF.ice" "$(SLICEPARSERLIB)" + "$(SLICE2PY)" $(SLICE2PYFLAGS) --prefix Ice_ --no-package "$(slicedir)/Ice/ValueFactoryF.ice" + Ice_Version_ice.py: "$(slicedir)/Ice/Version.ice" "$(SLICEPARSERLIB)" "$(SLICE2PY)" $(SLICE2PYFLAGS) --prefix Ice_ --no-package "$(slicedir)/Ice/Version.ice" diff --git a/python/test/Ice/exceptions/AllTests.py b/python/test/Ice/exceptions/AllTests.py index 4522a0de731..4df5e5d4dd3 100644 --- a/python/test/Ice/exceptions/AllTests.py +++ b/python/test/Ice/exceptions/AllTests.py @@ -26,13 +26,10 @@ class ServantLocatorI(Ice.ServantLocator): def deactivate(self, category): pass -class ObjectFactoryI(Ice.ObjectFactory): +class ValueFactoryI(Ice.ValueFactory): def create(id): return None - def destroy(): - pass - class CallbackBase: def __init__(self): self._called = False @@ -273,10 +270,10 @@ def allTests(communicator): sys.stdout.write("testing object factory registration exception... ") sys.stdout.flush() - of = ObjectFactoryI() - communicator.addObjectFactory(of, "x") + vf = ValueFactoryI() + communicator.addValueFactory(vf, "x") try: - communicator.addObjectFactory(of, "x") + communicator.addValueFactory(vf, "x") test(false) except Ice.AlreadyRegisteredException: pass diff --git a/python/test/Ice/objects/AllTests.py b/python/test/Ice/objects/AllTests.py index 3d46a6ca643..69296510fd4 100644 --- a/python/test/Ice/objects/AllTests.py +++ b/python/test/Ice/objects/AllTests.py @@ -9,7 +9,7 @@ import Ice, Test, TestI, sys -class MyObjectFactory(Ice.ObjectFactory): +class MyValueFactory(Ice.ValueFactory): def create(self, type): if type == '::Test::B': return TestI.BI() @@ -29,8 +29,11 @@ class MyObjectFactory(Ice.ObjectFactory): return TestI.HI() assert(False) # Should never be reached - def destroy(self): - # Nothing to do +class MyObjectFactory(Ice.ObjectFactory): + def create(self, type): + return None + + def destroy(): pass def test(b): @@ -38,15 +41,17 @@ def test(b): raise RuntimeError('test assertion failed') def allTests(communicator): - factory = MyObjectFactory() - communicator.addObjectFactory(factory, '::Test::B') - communicator.addObjectFactory(factory, '::Test::C') - communicator.addObjectFactory(factory, '::Test::D') - communicator.addObjectFactory(factory, '::Test::E') - communicator.addObjectFactory(factory, '::Test::F') - communicator.addObjectFactory(factory, '::Test::I') - communicator.addObjectFactory(factory, '::Test::J') - communicator.addObjectFactory(factory, '::Test::H') + factory = MyValueFactory() + communicator.addValueFactory(factory, '::Test::B') + communicator.addValueFactory(factory, '::Test::C') + communicator.addValueFactory(factory, '::Test::D') + communicator.addValueFactory(factory, '::Test::E') + communicator.addValueFactory(factory, '::Test::F') + communicator.addValueFactory(factory, '::Test::I') + communicator.addValueFactory(factory, '::Test::J') + communicator.addValueFactory(factory, '::Test::H') + + communicator.addObjectFactory(MyObjectFactory(), "TestOF") sys.stdout.write("testing stringToProxy... ") sys.stdout.flush() @@ -67,19 +72,19 @@ def allTests(communicator): b1 = initial.getB1() test(b1) print("ok") - + sys.stdout.write("getting B2... ") sys.stdout.flush() b2 = initial.getB2() test(b2) print("ok") - + sys.stdout.write("getting C... ") sys.stdout.flush() c = initial.getC() test(c) print("ok") - + sys.stdout.write("getting D... ") sys.stdout.flush() d = initial.getD() @@ -97,7 +102,7 @@ def allTests(communicator): test(f.e2.checkValues()) test(f._e1.checkValues()) print("ok") - + sys.stdout.write("getting I, J, H... ") sys.stdout.flush() i = initial.getI() @@ -107,7 +112,7 @@ def allTests(communicator): h = initial.getH() test(isinstance(h, Test.H)) print("ok") - + sys.stdout.write("getting D1... ") sys.stdout.flush() d1 = initial.getD1(Test.D1(Test.A1("a1"), Test.A1("a2"), Test.A1("a3"), Test.A1("a4"))); @@ -116,7 +121,7 @@ def allTests(communicator): test(d1.a3.name == "a3") test(d1.a4.name == "a4") print("ok") - + sys.stdout.write("throw EDerived... ") sys.stdout.flush() try: @@ -135,7 +140,7 @@ def allTests(communicator): initial.setI(TestI.JI()) initial.setI(TestI.HI()) print("ok") - + sys.stdout.write("checking consistency... ") sys.stdout.flush() test(b1 != b2) @@ -170,7 +175,7 @@ def allTests(communicator): test(c) test(d) print("ok") - + sys.stdout.write("checking consistency... ") sys.stdout.flush() test(b1 != b2) @@ -220,7 +225,7 @@ def allTests(communicator): print("ok") # Don't run this test with collocation, this should work with collocation - # but the test isn't written to support it (we'd need support for the + # but the test isn't written to support it (we'd need support for the # streaming interface) if initial.ice_getConnection(): sys.stdout.write("testing UnexpectedObjectException... ") @@ -244,4 +249,14 @@ def allTests(communicator): test(False) print("ok") + sys.stdout.write("testing getting ObjectFactory... ") + sys.stdout.flush() + test(communicator.findObjectFactory("TestOF") != None) + print("ok") + + sys.stdout.write("testing getting ObjectFactory as ValueFactory... ") + sys.stdout.flush() + test(communicator.findValueFactory("TestOF") != None) + print("ok") + return initial diff --git a/python/test/Ice/objects/Server.py b/python/test/Ice/objects/Server.py index d988b501d14..eb4df06fc5a 100755 --- a/python/test/Ice/objects/Server.py +++ b/python/test/Ice/objects/Server.py @@ -15,7 +15,7 @@ Ice.loadSlice('Test.ice') Ice.loadSlice('ServerPrivate.ice') import Test, TestI -class MyObjectFactory(Ice.ObjectFactory): +class MyValueFactory(Ice.ValueFactory): def create(self, type): if type == '::Test::I': return TestI.II() @@ -25,15 +25,11 @@ class MyObjectFactory(Ice.ObjectFactory): return TestI.HI() assert(False) # Should never be reached - def destroy(self): - # Nothing to do - pass - def run(args, communicator): - factory = MyObjectFactory() - communicator.addObjectFactory(factory, '::Test::I') - communicator.addObjectFactory(factory, '::Test::J') - communicator.addObjectFactory(factory, '::Test::H') + factory = MyValueFactory() + communicator.addValueFactory(factory, '::Test::I') + communicator.addValueFactory(factory, '::Test::J') + communicator.addValueFactory(factory, '::Test::H') communicator.getProperties().setProperty("TestAdapter.Endpoints", "default -p 12010") adapter = communicator.createObjectAdapter("TestAdapter") diff --git a/python/test/Ice/slicing/objects/AllTests.py b/python/test/Ice/slicing/objects/AllTests.py index c73a8df0b01..15f90497304 100644 --- a/python/test/Ice/slicing/objects/AllTests.py +++ b/python/test/Ice/slicing/objects/AllTests.py @@ -68,14 +68,14 @@ class Callback(CallbackBase): test(False) def exception_SBSUnknownDerivedAsSBaseCompact(self, ex): - test(isinstance(ex, Ice.NoObjectFactoryException)) + test(isinstance(ex, Ice.NoValueFactoryException)) self.called() def response_SUnknownAsObject10(self, o): test(False) def exception_SUnknownAsObject10(self, exc): - test(exc.ice_name() == "Ice::NoObjectFactoryException") + test(exc.ice_name() == "Ice::NoValueFactoryException") self.called() def response_SUnknownAsObject11(self, o): @@ -359,15 +359,12 @@ class PNodeI(Test.PNode): def __del__(self): PNodeI.counter = PNodeI.counter - 1 -class NodeFactoryI(Ice.ObjectFactory): +class NodeFactoryI(Ice.ValueFactory): def create(self, id): if id == Test.PNode.ice_staticId(): return PNodeI() return None - def destroy(self): - pass - class PreservedI(Test.Preserved): counter = 0 @@ -377,15 +374,12 @@ class PreservedI(Test.Preserved): def __del__(self): PreservedI.counter = PreservedI.counter - 1 -class PreservedFactoryI(Ice.ObjectFactory): +class PreservedFactoryI(Ice.ValueFactory): def create(self, id): if id == Test.Preserved.ice_staticId(): return PreservedI() return None - def destroy(self): - pass - def allTests(communicator): obj = communicator.stringToProxy("Test:default -p 12010") t = Test.TestIntfPrx.checkedCast(obj) @@ -492,7 +486,7 @@ def allTests(communicator): test(False) except Ice.OperationNotExistException: pass - except Ice.NoObjectFactoryException: + except Ice.NoValueFactoryException: # Expected. pass except: @@ -530,7 +524,7 @@ def allTests(communicator): test(isinstance(o, Ice.UnknownSlicedObject)) test(o.unknownTypeId == "::Test::SUnknown") t.checkSUnknown(o) - except Ice.NoObjectFactoryException: + except Ice.NoValueFactoryException: test(t.ice_getEncodingVersion() == Ice.Encoding_1_0) except Ice.Exception: test(False) @@ -1579,7 +1573,7 @@ def allTests(communicator): t.ice_encodingVersion(Ice.Encoding_1_0).checkPBSUnknown(p) except Ice.OperationNotExistException: pass - + print("ok") sys.stdout.write("preserved classes (AMI)... ") @@ -1674,7 +1668,7 @@ def allTests(communicator): # UCNode. This provides an easy way to determine how many # unmarshaled instances currently exist. # - communicator.addObjectFactory(NodeFactoryI(), Test.PNode.ice_staticId()) + communicator.addValueFactory(NodeFactoryI(), Test.PNode.ice_staticId()) # # Relay a graph through the server. This test uses a preserved class @@ -1761,7 +1755,7 @@ def allTests(communicator): # Preserved. This provides an easy way to determine how many # unmarshaled instances currently exist. # - communicator.addObjectFactory(PreservedFactoryI(), Test.Preserved.ice_staticId()) + communicator.addValueFactory(PreservedFactoryI(), Test.Preserved.ice_staticId()) # # Obtain a preserved object from the server where the most-derived |