You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
arts/mcop/object.cc

1529 lines
40 KiB

/*
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., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, 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()
{
/*
* tqinvalidate 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;
}