diff options
Diffstat (limited to 'mcop/object.cc')
-rw-r--r-- | mcop/object.cc | 1528 |
1 files changed, 1528 insertions, 0 deletions
diff --git a/mcop/object.cc b/mcop/object.cc new file mode 100644 index 0000000..9f01912 --- /dev/null +++ b/mcop/object.cc @@ -0,0 +1,1528 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "object.h" +#include "dispatcher.h" +#include "flowsystem.h" +#include "weakreference.h" +#include "namedstore.h" +#include "debug.h" +#include "anyref.h" +#include <stdio.h> +#include <iostream> +#include <cstdlib> + +using namespace std; +using namespace Arts; + +namespace Arts { + class AttributeSlotBind; +} + +class Arts::ObjectInternalData { +public: + struct MethodTableEntry { + union { + DispatchFunction dispatcher; + OnewayDispatchFunction onewayDispatcher; + DynamicDispatchFunction dynamicDispatcher; + } dispFunc; + enum { dfNormal, dfOneway, dfDynamic } dispatchStyle; + void *object; + MethodDef methodDef; + }; + + list<WeakReferenceBase *> weakReferences; + NamedStore<Arts::Object> children; + bool stubForLocalObject; + + // for _skel classes only: + bool methodTableInit; + std::vector<MethodTableEntry> methodTable; + list<AttributeSlotBind *> attributeSlots; +}; + +struct Object_base::ObjectStreamInfo { + string name; + long flags; + void *ptr; +}; + +/*****************************************************************************/ +/* the following methods/classes are necessary for attribute notifications */ +/*****************************************************************************/ + +namespace Arts { + class AttributeDataPacket : public GenericDataPacket { + public: + Buffer b; + AttributeDataPacket(GenericDataChannel *channel) + : GenericDataPacket(channel) + { + size = 0; + b.writeLong(0); + } + void add(const AnyConstRef& r) + { + r.write(&b); + b.patchLong(0,++size); + } + + void ensureCapacity(int) + { + } + void read(Buffer& stream) + { + vector<mcopbyte> all; + size = stream.readLong(); + b.patchLong(0,size); + stream.read(all,stream.remaining()); + b.write(all); + } + void write(Buffer& stream) + { + vector<mcopbyte> all; + b.rewind(); + b.read(all,b.remaining()); + stream.write(all); + } + }; + class AttributeSlotBind : public GenericAsyncStream { + public: + GenericDataPacket *createPacket(int) + { + return allocPacket(); + } + AttributeDataPacket *allocPacket() + { + return new AttributeDataPacket(channel); + } + + void freePacket(GenericDataPacket *packet) + { + delete packet; + } + + GenericAsyncStream *createNewStream() + { + return new AttributeSlotBind(); + } + + virtual ~AttributeSlotBind() + { + } + + string method; + bool output; + }; +} + +bool Object_skel::_initAttribute(const AttributeDef& attribute) +{ + long flags = attribute.flags; + + if(flags & attributeAttribute) + { + flags |= attributeStream | streamAsync; + flags &= ~attributeAttribute; + } + else + { + arts_warning("attribute init on stream %s", attribute.name.c_str()); + return false; + } + + list<AttributeSlotBind *>::iterator i; + for(i = _internalData->attributeSlots.begin(); + i != _internalData->attributeSlots.end(); i++) + { + AttributeSlotBind *b = *i; + if(b->method == "_set_"+attribute.name + || b->method == attribute.name + "_changed") + { + arts_warning("double attribute init %s",b->method.c_str()); + return false; + } + } + if(flags & streamIn) + { + AttributeSlotBind *b = new AttributeSlotBind(); + b->output = false; + b->method = "_set_"+attribute.name; + _internalData->attributeSlots.push_back(b); + + _scheduleNode->initStream(attribute.name, b, flags & (~streamOut)); + } + if(flags & streamOut) + { + string changed = attribute.name + "_changed"; + AttributeSlotBind *b = new AttributeSlotBind(); + b->output = true; + b->method = changed; + _internalData->attributeSlots.push_back(b); + + _scheduleNode->initStream(changed, b, flags & (~streamIn)); + } + return true; +} + +void Object_skel::_defaultNotify(const Notification& notification) +{ + list<AttributeSlotBind *>::iterator i; + list<AttributeSlotBind *>& slots = _internalData->attributeSlots; + + for(i = slots.begin(); i != slots.end(); i++) + { + if((*i)->notifyID() == notification.ID) + { + GenericDataPacket *dp = (GenericDataPacket *)notification.data; + Buffer params; + + dp->write(params); + + if(!_internalData->methodTableInit) + { + // take care that the object base methods are at the beginning + Object_skel::_buildMethodTable(); + _buildMethodTable(); + _internalData->methodTableInit = true; + } + + typedef ObjectInternalData::MethodTableEntry MTE; + vector<MTE>::iterator mti; + + for(mti = _internalData->methodTable.begin(); + mti != _internalData->methodTable.end(); mti++) + { + if(mti->methodDef.name == (*i)->method) + { + Buffer result; + + long count = params.readLong(); + while(params.remaining()) + { + if(mti->dispatchStyle == MTE::dfNormal) + { + mti->dispFunc.dispatcher(mti->object, ¶ms, &result); + } + else if(mti->dispatchStyle == MTE::dfDynamic) + { + long methodID; + methodID = mti - _internalData->methodTable.begin(); + mti->dispFunc.dynamicDispatcher(mti->object, methodID, + ¶ms, &result); + } + else + { + arts_assert(0); + } + count--; + } + arts_assert(count == 0); + } + } + dp->processed(); + } + } +} + +void Object_skel::notify(const Notification& notification) +{ + _copy(); + _defaultNotify(notification); + _release(); +} + +/* for simplicity and efficiency, enums are emitted as normal "long" values, + * so that finding out/using the enum type via value.type() is not be possible + */ +void Object_skel::_emit_changed(const char *attrib, const AnyConstRef& value) +{ + list<AttributeSlotBind *>::iterator i; + list<AttributeSlotBind *>& slots = _internalData->attributeSlots; + + for(i = slots.begin(); i != slots.end(); i++) + { + if((*i)->method == attrib) + { + AttributeDataPacket *adp = + (AttributeDataPacket *)(*i)->createPacket(1); + adp->add(value); + adp->send(); + return; + } + } +} + + +bool Object_skel::_generateSlots(const std::string& name, + const std::string& interface) +{ + InterfaceDef d = _queryInterface(interface); + vector<string>::iterator ii; + for(ii = d.inheritedInterfaces.begin(); + ii != d.inheritedInterfaces.end(); ii++) + { + if(_generateSlots(name, *ii)) return true; + } + + vector<AttributeDef>::iterator ai; + for(ai = d.attributes.begin(); ai != d.attributes.end(); ai++) + { + if(ai->flags & attributeAttribute) + { + if((ai->flags & streamIn && ai->name == name) + || (ai->flags & streamOut && ai->name+"_changed" == name)) + { + _initAttribute(*ai); + return true; + } + } + } + return false; +} + +bool Object_skel::_QueryInitStreamFunc(Object_skel *skel, const + std::string& name) +{ + /* + * this function + * + * checks if there is a stream which should be added called <name>, + * and returns true if it in fact added a stream, so that requesting + * function needs to retry + */ + bool result = skel->_generateSlots(name, skel->_interfaceName()); + if(!result) + { + arts_warning("used stream %s on object %s, which doesn't seem to exist", + name.c_str(), skel->_interfaceName().c_str()); + } + return result; +} + +/*****************************************************************************/ + + +/* + * Object: common for every object + */ + +long Object_base::_staticObjectCount = 0; + +Object_base::Object_base() : _deleteOk(false), _scheduleNode(0), _nextNotifyID(1), + _refCnt(1) +{ + _internalData = new Arts::ObjectInternalData(); + _internalData->stubForLocalObject = false; + _staticObjectCount++; +} + +void Object_base::_destroy() +{ + _deleteOk = true; + + if(_scheduleNode && !_internalData->stubForLocalObject) + { + if(_scheduleNode->remoteScheduleNode()) + { + delete _scheduleNode; + } + else + { + FlowSystem_impl *fs = Dispatcher::the()->flowSystem(); + assert(fs); + + fs->removeObject(_scheduleNode); + } + } + delete this; +} + +Object_base::~Object_base() +{ + if(!_deleteOk) + { + arts_fatal("reference counting violation - you may not call delete " + "manually - use _release() instead"); + } + assert(_deleteOk); + + /* remove attribute slots */ + list<AttributeSlotBind *>::iterator ai; + for(ai = _internalData->attributeSlots.begin(); + ai != _internalData->attributeSlots.end(); ai++) + { + delete (*ai); + } + + /* clear stream list */ + list<ObjectStreamInfo *>::iterator osii; + for(osii = _streamList.begin(); osii != _streamList.end(); osii++) + delete (*osii); + + /* inform weak references that we don't exist any longer */ + while(!_internalData->weakReferences.empty()) + _internalData->weakReferences.front()->release(); + + /* inform notification manager that we don't exist any longer */ + NotificationManager::the()->removeClient(this); + + delete _internalData; + _staticObjectCount--; +} + +ScheduleNode *Object_base::_node() +{ + if(!_scheduleNode) + { + switch(_location()) + { + case objectIsLocal: + { + FlowSystem_impl *fs = Dispatcher::the()->flowSystem(); + assert(fs); + _scheduleNode = fs->addObject(_skel()); + + /* init streams */ + + list<ObjectStreamInfo *>::iterator osii; + for(osii = _streamList.begin(); osii != _streamList.end(); osii++) + { + _scheduleNode->initStream((*osii)->name,(*osii)->ptr,(*osii)->flags); + } + _scheduleNode->initStream("QueryInitStreamFunc", + (void *)Object_skel::_QueryInitStreamFunc, -1); + } + break; + + case objectIsRemote: + { + /* + * if we're just a stub to an object that is local inside + * this process, then we don't create a new schedule node, + * but find the one associated with the implementation + * + * (this happens for instance for objects implemented as + * artsbuilder structures) + */ + if(_internalData->stubForLocalObject) + { + Dispatcher *disp = Dispatcher::the(); + Object_skel *localObject; + + localObject = disp->getLocalObject(_stub()->_objectID); + arts_assert(localObject); + + _scheduleNode = localObject->_node(); + localObject->_release(); + } + else + { + _scheduleNode = new RemoteScheduleNode(_stub()); + } + } + break; + } + + assert(_scheduleNode); + } + return _scheduleNode; +} + +bool Object_base::_isEqual(Object_base *object) const +{ + return (_internalObjectID == object->_internalObjectID); +} + +void *Object_base::_cast(unsigned long iid) +{ + if(iid == Object_base::_IID) return (Object *)this; + return 0; +} + +void *Object_base::_cast(const std::string& interface) +{ + return _cast(MCOPUtils::makeIID(interface)); +} + +bool Object_base::_error() +{ + // no error as default ;) + return false; +} + +Object_skel *Object_base::_skel() +{ + assert(false); + return 0; +} + +Object_stub *Object_base::_stub() +{ + assert(false); + return 0; +} + +Object_stub *Object_stub::_stub() +{ + return this; +} + +Object_base::ObjectLocation Object_stub::_location() const +{ + return objectIsRemote; +} + +Object_skel *Object_skel::_skel() +{ + return this; +} + +Object_base::ObjectLocation Object_skel::_location() const +{ + return objectIsLocal; +} + +void Object_skel::_initStream(const string& name, void *ptr, long flags) +{ + ObjectStreamInfo *osi = new ObjectStreamInfo; + osi->name = name; + osi->ptr = ptr; + osi->flags = flags; + _streamList.push_back(osi); +} + +void Object_base::calculateBlock(unsigned long) +{ +} + +string Object_base::_interfaceName() +{ + assert(0); // derived classes *must* override this + return ""; +} + +Buffer *Object_base::_allocCustomMessage(long /*handlerID*/) +{ + assert(0); + return 0; +} + +void Object_base::_sendCustomMessage(Buffer *buffer) +{ + assert(0); + delete buffer; +} + +// Default I/O: nothing at this level, use child virtuals +vector<std::string> Object_base::_defaultPortsIn() const +{ + vector<std::string> ret; + return ret; +} +vector<std::string> Object_base::_defaultPortsOut() const +{ + vector<std::string> ret; + return ret; +} + +// Weak References + +void Object_base::_addWeakReference(WeakReferenceBase *b) +{ + _internalData->weakReferences.push_back(b); +} + +void Object_base::_removeWeakReference(WeakReferenceBase *b) +{ + _internalData->weakReferences.remove(b); +} + +/* + * Stuff for object skeletons + */ + +Object_skel::Object_skel() :_remoteSendCount(0), _remoteSendUpdated(false) +{ + _objectID = Dispatcher::the()->addObject(this); + _connection = Dispatcher::the()->loopbackConnection(); + _internalData->methodTableInit = false; + +/* big enough for our header + 0x + needed number of hex characters + ending NULL */ + char ioid[7 + 2*sizeof(void *)+1]; + sprintf(ioid,"SKEL:%p",(void *)this); + _internalObjectID = ioid; +} + +Object_skel::~Object_skel() +{ + Dispatcher::the()->removeObject(_objectID); +} + +// flow system + +FlowSystem Object_skel::_flowSystem() +{ + FlowSystem_base *fs = Dispatcher::the()->flowSystem(); + if(fs) + return FlowSystem::_from_base(fs->_copy()); + else + return FlowSystem::null(); +} + +// reference counting + +void Object_skel::_release() +{ + arts_return_if_fail(_refCnt > 0); + + _refCnt--; + if(_refCnt == 0) _destroy(); +} + +void Object_skel::_copyRemote() +{ + // cout << "_copyRemote();" << endl; + + _copy(); + _remoteSendCount++; + _remoteSendUpdated = true; +} + +void Object_skel::_releaseRemote() +{ + //cout << "_releaseRemote();" << endl; + + Connection *conn = Dispatcher::the()->activeConnection(); + list<Connection *>::iterator i; + bool found = false; + + for(i=_remoteUsers.begin(); !found && i != _remoteUsers.end(); i++) + { + found = (*i) == conn; + if(found) + { + _remoteUsers.erase(i); + break; + } + } + assert(found); + _release(); +} + +void Object_skel::_useRemote() +{ + //cout << "_useRemote();" << endl; + + Connection *conn = Dispatcher::the()->activeConnection(); + if(_remoteSendCount == 0) + { + arts_warning("_useRemote without prior _copyRemote() - this might fail sometimes"); + _copyRemote(); + } + + _remoteSendCount--; + _remoteUsers.push_back(conn); +} + +/* + * This is needed when we've received an object from wire which we now + * hold locally. Of course it has been _copyRemote()d (rightly so), but + * we will not use it remotely, so we need to cancel the _copyRemote(). + * + * Added to _base due to BC. + */ +void Object_base::_cancelCopyRemote() +{ + assert(_location() == objectIsLocal); + + if(_skel()->_remoteSendCount == 0) + { + arts_warning("_cancelCopyRemote without prior _copyRemote() - this might fail sometimes"); + } + else + { + _skel()->_remoteSendCount--; + _release(); + } +} + +void Object_skel::_disconnectRemote(Connection *conn) +{ + //cout << "_disconnectRemote();" << endl; + + int rcount = 0; + list<Connection *>::iterator i; + + i=_remoteUsers.begin(); + while(i != _remoteUsers.end()) + { + if((*i) == conn) + { + _remoteUsers.erase(i); + i = _remoteUsers.begin(); + rcount++; + } + else i++; + } + + while(rcount) { + arts_debug("client disconnected: dropped one object reference"); + rcount--; + _release(); + } + /* warning: object may not exist any longer here */ +} + +void Object_skel::_referenceClean() +{ + if(_remoteSendCount > 0) + { + if(_remoteSendUpdated) + { + // this ensures that every client gets at least five + // seconds to connect + _remoteSendUpdated = false; + } + else + { + int rcount = _remoteSendCount; + + arts_debug("_referenceClean: found unused object marked by " + "_copyRemote => releasing"); + + while(rcount--) + { + _remoteSendCount--; + _release(); + } + } + /* warning: object may be gone here */ + } +} + +string Object_skel::_toString() +{ + return Dispatcher::the()->objectToString(_objectID); +} + +string Object_skel::_interfaceName() +{ + assert(0); // derived classes *must* override this + return ""; +} + +string Object_skel::_interfaceNameSkel() +{ + // derived classes *must* override this, but we return a sane value here + // anyway, because DynamicSkeleton depends on this + return "Arts::Object"; +} + +bool Object_skel::_isCompatibleWith(const std::string& interfacename) +{ + if (interfacename=="Arts::Object") return true; + return false; +} + +InterfaceDef Object_skel::_queryInterface(const string& name) +{ + return Dispatcher::the()->interfaceRepo().queryInterface(name); +} + +TypeDef Object_skel::_queryType(const string& name) +{ + return Dispatcher::the()->interfaceRepo().queryType(name); +} + +EnumDef Object_skel::_queryEnum(const string& name) +{ + return Dispatcher::the()->interfaceRepo().queryEnum(name); +} + +// Aggregation +std::string Object_skel::_addChild(Arts::Object child, const std::string& name) +{ + return _internalData->children.put(name,child); +} + +bool Object_skel::_removeChild(const std::string& name) +{ + return _internalData->children.remove(name); +} + +Arts::Object Object_skel::_getChild(const std::string& name) +{ + Arts::Object result; + if(_internalData->children.get(name,result)) + return result; + else + return Arts::Object::null(); +} + +std::vector<std::string> *Object_skel::_queryChildren() +{ + return _internalData->children.contents(); +} + +void Object_skel::_addMethod(DispatchFunction disp, void *obj, + const MethodDef& md) +{ + Arts::ObjectInternalData::MethodTableEntry me; + me.dispFunc.dispatcher = disp; + me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfNormal; + me.object = obj; + me.methodDef = md; + _internalData->methodTable.push_back(me); +} + +void Object_skel::_addMethod(OnewayDispatchFunction disp, void *obj, + const MethodDef& md) +{ + Arts::ObjectInternalData::MethodTableEntry me; + me.dispFunc.onewayDispatcher = disp; + me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfOneway; + me.object = obj; + me.methodDef = md; + _internalData->methodTable.push_back(me); +} + +void Object_skel::_addMethod(DynamicDispatchFunction disp, void *obj, + const MethodDef& md) +{ + Arts::ObjectInternalData::MethodTableEntry me; + me.dispFunc.dynamicDispatcher = disp; + me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfDynamic; + me.object = obj; + me.methodDef = md; + _internalData->methodTable.push_back(me); +} + + +long Object_skel::_addCustomMessageHandler(OnewayDispatchFunction handler, + void *obj) +{ + if(!_internalData->methodTableInit) + { + // take care that the object base methods are at the beginning + Object_skel::_buildMethodTable(); + _buildMethodTable(); + _internalData->methodTableInit = true; + } + Arts::ObjectInternalData::MethodTableEntry me; + me.dispFunc.onewayDispatcher = handler; + me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfOneway; + me.object = obj; + me.methodDef.name = "_userdefined_customdatahandler"; + _internalData->methodTable.push_back(me); + return _internalData->methodTable.size()-1; +} + +void Object_skel::_dispatch(Buffer *request, Buffer *result,long methodID) +{ + if(!_internalData->methodTableInit) + { + // take care that the object base methods are at the beginning + Object_skel::_buildMethodTable(); + _buildMethodTable(); + _internalData->methodTableInit = true; + } + + const ObjectInternalData::MethodTableEntry& me + = _internalData->methodTable[methodID]; + + if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfNormal) + me.dispFunc.dispatcher(me.object, request, result); + else if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfDynamic) + me.dispFunc.dynamicDispatcher(me.object, methodID, request, result); + else + { + arts_assert(0); + } +} + +void Object_skel::_dispatch(Buffer *request,long methodID) +{ + if(!_internalData->methodTableInit) + { + // take care that the object base methods are at the beginning + Object_skel::_buildMethodTable(); + _buildMethodTable(); + _internalData->methodTableInit = true; + } + const ObjectInternalData::MethodTableEntry& me + = _internalData->methodTable[methodID]; + + if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfOneway) + me.dispFunc.onewayDispatcher(me.object, request); + else if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfDynamic) + me.dispFunc.dynamicDispatcher(me.object, methodID, request, 0); + else + { + arts_assert(0); + } +} + +long Object_skel::_lookupMethod(const MethodDef& md) +{ + long mcount = 0; + + if(!_internalData->methodTableInit) + { + // take care that the object base methods are at the beginning + Object_skel::_buildMethodTable(); + _buildMethodTable(); + _internalData->methodTableInit = true; + } + + vector<Arts::ObjectInternalData::MethodTableEntry>::iterator i; + for(i=_internalData->methodTable.begin(); i != _internalData->methodTable.end(); i++) + { + MethodDef& mdm = i->methodDef; + if(mdm.name == md.name && mdm.type == md.type) + { + /* TODO: compare signature + vector<ParamDef *>::const_iterator j,k; + j = md.signature.begin(); + k = mdm.signature.begin(); + while(j != md.signature.end() && (*j) == (*k)) + { + j++; + k++; + } + + if(j == md.signature.end() && k == mdm.signature.end()) + */ + return mcount; + } + mcount++; + } + arts_warning("_lookupMethod %s %s failed this might be caused by " + "incompatible IDL files and is likely to result in crashes", + md.type.c_str(),md.name.c_str()); + return -1; +} + +const MethodDef& Object_skel::_dsGetMethodDef(long methodID) +{ + if(!_internalData->methodTableInit) + { + // take care that the object base methods are at the beginning + Object_skel::_buildMethodTable(); + _buildMethodTable(); + _internalData->methodTableInit = true; + } + return _internalData->methodTable[methodID].methodDef; +} + +// _lookupMethod +static void _dispatch_Arts_Object_00(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + Arts::MethodDef methodDef(*request); + result->writeLong(((Arts::Object_skel *)object)->_lookupMethod(methodDef)); +} + +// _interfaceName +static void _dispatch_Arts_Object_01(void *object, Arts::Buffer *, Arts::Buffer *result) +{ + result->writeString(((Arts::Object_skel *)object)->_interfaceName()); +} + +// _queryInterface +static void _dispatch_Arts_Object_02(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + std::string name; + request->readString(name); + Arts::InterfaceDef _returnCode = ((Arts::Object_skel *)object)->_queryInterface(name); + _returnCode.writeType(*result); +} + +// _queryType +static void _dispatch_Arts_Object_03(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + std::string name; + request->readString(name); + Arts::TypeDef _returnCode = ((Arts::Object_skel *)object)->_queryType(name); + _returnCode.writeType(*result); +} + +// _queryEnum +static void _dispatch_Arts_Object_04(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + std::string name; + request->readString(name); + Arts::EnumDef _returnCode = ((Arts::Object_skel *)object)->_queryEnum(name); + _returnCode.writeType(*result); +} + +// _toString +static void _dispatch_Arts_Object_05(void *object, Arts::Buffer *, Arts::Buffer *result) +{ + result->writeString(((Arts::Object_skel *)object)->_toString()); +} + +// _isCompatibleWith +static void _dispatch_Arts_Object_06(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + std::string interfacename; + request->readString(interfacename); + result->writeBool(((Arts::Object_skel *)object)->_isCompatibleWith(interfacename)); +} + +// _copyRemote +static void _dispatch_Arts_Object_07(void *object, Arts::Buffer *, Arts::Buffer *) +{ + ((Arts::Object_skel *)object)->_copyRemote(); +} + +// _useRemote +static void _dispatch_Arts_Object_08(void *object, Arts::Buffer *, Arts::Buffer *) +{ + ((Arts::Object_skel *)object)->_useRemote(); +} + +// _releaseRemote +static void _dispatch_Arts_Object_09(void *object, Arts::Buffer *, Arts::Buffer *) +{ + ((Arts::Object_skel *)object)->_releaseRemote(); +} + +// _addChild +static void _dispatch_Arts_Object_10(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + Arts::Object_base* _temp_child; + readObject(*request,_temp_child); + Arts::Object child = Arts::Object::_from_base(_temp_child); + std::string name; + request->readString(name); + result->writeString(((Arts::Object_skel *)object)->_addChild(child,name)); +} + +// _removeChild +static void _dispatch_Arts_Object_11(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + std::string name; + request->readString(name); + result->writeBool(((Arts::Object_skel *)object)->_removeChild(name)); +} + +// _getChild +static void _dispatch_Arts_Object_12(void *object, Arts::Buffer *request, Arts::Buffer *result) +{ + std::string name; + request->readString(name); + Arts::Object returnCode = ((Arts::Object_skel *)object)->_getChild(name); + writeObject(*result,returnCode._base()); +} + +// _queryChildren +static void _dispatch_Arts_Object_13(void *object, Arts::Buffer *, Arts::Buffer *result) +{ + std::vector<std::string> *_returnCode = ((Arts::Object_skel *)object)->_queryChildren(); + result->writeStringSeq(*_returnCode); + delete _returnCode; +} + +// _get__flowSystem +static void _dispatch_Arts_Object_14(void *object, Arts::Buffer *, Arts::Buffer *result) +{ + Arts::FlowSystem returnCode = ((Arts::Object_skel *)object)->_flowSystem(); + writeObject(*result,returnCode._base()); +} + +void Arts::Object_skel::_buildMethodTable() +{ + Arts::Buffer m; + m.fromString( + "MethodTable:0000000e5f6c6f6f6b75704d6574686f6400000000056c6f6e6700" + "000000020000000100000010417274733a3a4d6574686f64446566000000000a6d" + "6574686f644465660000000000000000000000000f5f696e746572666163654e61" + "6d650000000007737472696e6700000000020000000000000000000000105f7175" + "657279496e746572666163650000000013417274733a3a496e7465726661636544" + "656600000000020000000100000007737472696e6700000000056e616d65000000" + "0000000000000000000b5f717565727954797065000000000e417274733a3a5479" + "706544656600000000020000000100000007737472696e6700000000056e616d65" + "0000000000000000000000000b5f7175657279456e756d000000000e417274733a" + "3a456e756d44656600000000020000000100000007737472696e6700000000056e" + "616d650000000000000000000000000a5f746f537472696e670000000007737472" + "696e6700000000020000000000000000000000125f6973436f6d70617469626c65" + "576974680000000008626f6f6c65616e0000000002000000010000000773747269" + "6e67000000000e696e746572666163656e616d650000000000000000000000000c" + "5f636f707952656d6f74650000000005766f696400000000020000000000000000" + "0000000b5f75736552656d6f74650000000005766f696400000000020000000000" + "0000000000000f5f72656c6561736552656d6f74650000000005766f6964000000" + "000200000000000000000000000a5f6164644368696c640000000007737472696e" + "67000000000200000002000000076f626a65637400000000066368696c64000000" + "000000000007737472696e6700000000056e616d65000000000000000000000000" + "0d5f72656d6f76654368696c640000000008626f6f6c65616e0000000002000000" + "0100000007737472696e6700000000056e616d650000000000000000000000000a" + "5f6765744368696c6400000000076f626a65637400000000020000000100000007" + "737472696e6700000000056e616d650000000000000000000000000f5f71756572" + "794368696c6472656e00000000082a737472696e67000000000200000000000000" + "00000000115f6765745f5f666c6f7753797374656d0000000011417274733a3a46" + "6c6f7753797374656d00000000020000000000000000", + "MethodTable" + ); + _addMethod(_dispatch_Arts_Object_00,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_01,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_02,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_03,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_04,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_05,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_06,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_07,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_08,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_09,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_10,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_11,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_12,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_13,this,Arts::MethodDef(m)); + _addMethod(_dispatch_Arts_Object_14,this,Arts::MethodDef(m)); +} + +/* + * Stuff for object stubs + */ + +Object_stub::Object_stub() +{ + assert(0); // never use this constructor, as it doesn't assign an object ID +} + +Object_stub::Object_stub(Connection *connection, long objectID) +{ + _connection = connection; + _connection->_copy(); + _objectID = objectID; + _lookupCacheRandom = rand(); + + if(_connection == Dispatcher::the()->loopbackConnection()) + _internalData->stubForLocalObject = true; + + char ioid[128]; + sprintf(ioid,"STUB:%ld:%p",_objectID,(void *)connection); + _internalObjectID = ioid; +} + +Object_stub::~Object_stub() +{ + /* + * invalidate method lookup cache entries of this object, as it might + * happen, that another Object_stub is created just at the same position + */ + if(_lookupMethodCache) + { + for(long p=0;p<_lookupMethodCacheSize;p++) + { + if(_lookupMethodCache[p].obj == this) + _lookupMethodCache[p].obj = NULL; + } + } + _connection->_release(); +} + +bool Object_stub::_error() +{ + /* + * servers are trustworthy - they don't do things wrong (e.g. send + * wrong buffers or things like that) - however, if the connection is + * lost, this indicates that something went terrible wrong (probably + * the remote server crashed, or maybe the network is dead), and you + * can't rely on results of invocations any longer + */ + return _connection->broken(); +} + +void Object_stub::_release() +{ + arts_return_if_fail(_refCnt > 0); + + _refCnt--; + if(_refCnt == 0) + { + _releaseRemote(); + _destroy(); + } +} + +Object_base *Object_base::_create(const std::string& subClass) +{ + Object_skel *skel = ObjectManager::the()->create(subClass); + assert(skel); + return skel; +} + +Object_base *Object_base::_fromString(const string& objectref) +{ + Object_base *result = 0; + ObjectReference r; + + if(Dispatcher::the()->stringToObjectReference(r,objectref)) + { + result = (Object_base *)Dispatcher::the()->connectObjectLocal(r,"Object"); + if(!result) + { + Connection *conn = Dispatcher::the()->connectObjectRemote(r); + if(conn) + { + result = new Object_stub(conn,r.objectID); + result->_useRemote(); + } + } + } + return result; +} + +Object_base *Object_base::_fromReference(ObjectReference r, bool needcopy) +{ + Object_base *result; + result = (Object_base *)Dispatcher::the()->connectObjectLocal(r,"Object"); + if(result) + { + if(!needcopy) + result->_cancelCopyRemote(); + } + else + { + Connection *conn = Dispatcher::the()->connectObjectRemote(r); + if(conn) + { + result = new Object_stub(conn,r.objectID); + if(needcopy) result->_copyRemote(); + result->_useRemote(); + } + } + return result; +} + +string Object_stub::_interfaceName() +{ + long requestID; + Buffer *request, *result; + request = Dispatcher::the()->createRequest(requestID,_objectID,1); + // methodID = 1 => _interfaceName (always) + request->patchLength(); + _connection->qSendBuffer(request); + + result = Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return ""; // error + string returnCode; + result->readString(returnCode); + delete result; + return returnCode; +} + +InterfaceDef Object_stub::_queryInterface(const string& name) +{ + long requestID; + Buffer *request, *result; + request = Dispatcher::the()->createRequest(requestID,_objectID,2); + // methodID = 2 => _queryInterface (always) + request->writeString(name); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return InterfaceDef(); // error + InterfaceDef _returnCode(*result); + delete result; + return _returnCode; +} + +TypeDef Object_stub::_queryType(const string& name) +{ + long requestID; + Buffer *request, *result; + request = Dispatcher::the()->createRequest(requestID,_objectID,3); + // methodID = 3 => _queryType (always) + request->writeString(name); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return TypeDef(); // error + TypeDef _returnCode(*result); + delete result; + return _returnCode; +} + +EnumDef Object_stub::_queryEnum(const string& name) +{ + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,4); + // methodID = 4 => _queryEnum (always) + request->writeString(name); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return EnumDef(); // error occurred + EnumDef _returnCode(*result); + delete result; + return _returnCode; +} + +long Object_stub::_lookupMethod(const MethodDef& methodDef) +{ + long requestID; + Buffer *request, *result; + request = Dispatcher::the()->createRequest(requestID,_objectID,0); + // methodID = 0 => _lookupMethod (always) + methodDef.writeType(*request); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return 0; // error + long returnCode = result->readLong(); + delete result; + return returnCode; +} + +Object_stub::methodCacheEntry *Object_stub::_lookupMethodCache = 0; + +long Object_stub::_lookupMethodFast(const char *method) +{ + unsigned long c1 = (unsigned long)this; + unsigned long c2 = (unsigned long)method; + unsigned long pos = (c1^c2^_lookupCacheRandom)%_lookupMethodCacheSize; + /* FIXME this hashing method sucks. at a bare minimum, we're using only every 4th bin */ + + if(!_lookupMethodCache) + _lookupMethodCache = new methodCacheEntry[_lookupMethodCacheSize]; + + if(_lookupMethodCache[pos].obj == this && _lookupMethodCache[pos].method == method) + return _lookupMethodCache[pos].ID; + + Buffer _methodBuffer; + _methodBuffer.fromString(method,"method"); + long methodID = _lookupMethod(MethodDef(_methodBuffer)); + //cout << "methodID = " << methodID << endl; + + _lookupMethodCache[pos].obj = this; + _lookupMethodCache[pos].method = method; + _lookupMethodCache[pos].ID = methodID; + return methodID; +} + +// other (normal) methods without fixed location + +std::string Arts::Object_stub::_toString() +{ + long methodID = _lookupMethodFast("method:0000000a5f746f537472696e670000000007737472696e6700000000020000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return""; // error occurred + std::string returnCode; + result->readString(returnCode); + delete result; + return returnCode; +} + +bool Arts::Object_stub::_isCompatibleWith(const std::string& interfacename) +{ + long methodID = _lookupMethodFast("method:000000125f6973436f6d70617469626c65576974680000000008626f6f6c65616e00000000020000000100000007737472696e67000000000e696e746572666163656e616d65000000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->writeString(interfacename); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return false; // error occurred + bool returnCode = result->readBool(); + delete result; + return returnCode; +} + +void Arts::Object_stub::_copyRemote() +{ + long methodID = _lookupMethodFast("method:0000000c5f636f707952656d6f74650000000005766f696400000000020000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(result) delete result; +} + +void Arts::Object_stub::_useRemote() +{ + long methodID = _lookupMethodFast("method:0000000b5f75736552656d6f74650000000005766f696400000000020000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(result) delete result; +} + +void Arts::Object_stub::_releaseRemote() +{ + long methodID = _lookupMethodFast("method:0000000f5f72656c6561736552656d6f74650000000005766f696400000000020000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(result) delete result; +} + +std::string Arts::Object_stub::_addChild(Arts::Object child, const std::string& name) +{ + long methodID = _lookupMethodFast("method:0000000a5f6164644368696c640000000007737472696e67000000000200000002000000076f626a65637400000000066368696c64000000000000000007737472696e6700000000056e616d65000000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + writeObject(*request,child._base()); + request->writeString(name); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return""; // error occurred + std::string returnCode; + result->readString(returnCode); + delete result; + return returnCode; +} + +bool Arts::Object_stub::_removeChild(const std::string& name) +{ + long methodID = _lookupMethodFast("method:0000000d5f72656d6f76654368696c640000000008626f6f6c65616e00000000020000000100000007737472696e6700000000056e616d65000000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->writeString(name); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if(!result) return false; // error occurred + bool returnCode = result->readBool(); + delete result; + return returnCode; +} + +Arts::Object Arts::Object_stub::_getChild(const std::string& name) +{ + long methodID = _lookupMethodFast("method:0000000a5f6765744368696c6400000000076f626a65637400000000020000000100000007737472696e6700000000056e616d65000000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->writeString(name); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if (!result) return Arts::Object::null(); + Arts::Object_base* returnCode; + readObject(*result,returnCode); + delete result; + return Arts::Object::_from_base(returnCode); +} + +std::vector<std::string> * Arts::Object_stub::_queryChildren() +{ + long methodID = _lookupMethodFast("method:0000000f5f71756572794368696c6472656e00000000082a737472696e6700000000020000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + std::vector<std::string> *_returnCode = new std::vector<std::string>; + if(!result) return _returnCode; // error occurred + result->readStringSeq(*_returnCode); + delete result; + return _returnCode; +} + +Arts::FlowSystem Arts::Object_stub::_flowSystem() +{ + long methodID = _lookupMethodFast("method:000000115f6765745f5f666c6f7753797374656d0000000011417274733a3a466c6f7753797374656d00000000020000000000000000"); + long requestID; + Arts::Buffer *request, *result; + request = Arts::Dispatcher::the()->createRequest(requestID,_objectID,methodID); + request->patchLength(); + _connection->qSendBuffer(request); + + result = Arts::Dispatcher::the()->waitForResult(requestID,_connection); + if (!result) return Arts::FlowSystem::null(); + Arts::FlowSystem_base* returnCode; + readObject(*result,returnCode); + delete result; + return Arts::FlowSystem::_from_base(returnCode); +} + +/* + * custom messaging + */ + +Buffer *Object_stub::_allocCustomMessage(long handlerID) +{ + return Dispatcher::the()->createOnewayRequest(_objectID,handlerID); +} + +void Object_stub::_sendCustomMessage(Buffer *buffer) +{ + buffer->patchLength(); + _connection->qSendBuffer(buffer); +} + +unsigned long Object_base::_IID = MCOPUtils::makeIID("Object"); + +/* + * global cleanup + */ + +void Object_stub::_cleanupMethodCache() +{ + if(_lookupMethodCache) + { + delete[] _lookupMethodCache; + _lookupMethodCache = 0; + } +} + +namespace Arts { + static class Object_stub_Shutdown : public StartupClass { + public: + void startup() { } + void shutdown() { Object_stub::_cleanupMethodCache(); } + } The_Object_stub_Shutdown; +} |