summaryrefslogtreecommitdiffstats
path: root/mcop/object.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mcop/object.cc')
-rw-r--r--mcop/object.cc1528
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, &params, &result);
+ }
+ else if(mti->dispatchStyle == MTE::dfDynamic)
+ {
+ long methodID;
+ methodID = mti - _internalData->methodTable.begin();
+ mti->dispFunc.dynamicDispatcher(mti->object, methodID,
+ &params, &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;
+}