/* 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 #include #include 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 weakReferences; NamedStore children; bool stubForLocalObject; // for _skel classes only: bool methodTableInit; std::vector methodTable; list 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 all; size = stream.readLong(); b.patchLong(0,size); stream.read(all,stream.remaining()); b.write(all); } void write(Buffer& stream) { vector 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::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::iterator i; list& 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::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::iterator i; list& 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::iterator ii; for(ii = d.inheritedInterfaces.begin(); ii != d.inheritedInterfaces.end(); ii++) { if(_generateSlots(name, *ii)) return true; } vector::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 , * 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::iterator ai; for(ai = _internalData->attributeSlots.begin(); ai != _internalData->attributeSlots.end(); ai++) { delete (*ai); } /* clear stream list */ list::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::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 Object_base::_defaultPortsIn() const { vector ret; return ret; } vector Object_base::_defaultPortsOut() const { vector 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::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::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 *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::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::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 *_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 * 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 *_returnCode = new std::vector; 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; }