|
|
|
/*
|
|
|
|
|
|
|
|
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, ¶ms, &result);
|
|
|
|
}
|
|
|
|
else if(mti->dispatchStyle == MTE::dfDynamic)
|
|
|
|
{
|
|
|
|
long methodID;
|
|
|
|
methodID = mti - _internalData->methodTable.begin();
|
|
|
|
mti->dispFunc.dynamicDispatcher(mti->object, methodID,
|
|
|
|
¶ms, &result);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arts_assert(0);
|
|
|
|
}
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
arts_assert(count == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dp->processed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::notify(const Notification& notification)
|
|
|
|
{
|
|
|
|
_copy();
|
|
|
|
_defaultNotify(notification);
|
|
|
|
_release();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for simplicity and efficiency, enums are emitted as normal "long" values,
|
|
|
|
* so that finding out/using the enum type via value.type() is not be possible
|
|
|
|
*/
|
|
|
|
void Object_skel::_emit_changed(const char *attrib, const AnyConstRef& value)
|
|
|
|
{
|
|
|
|
list<AttributeSlotBind *>::iterator i;
|
|
|
|
list<AttributeSlotBind *>& slots = _internalData->attributeSlots;
|
|
|
|
|
|
|
|
for(i = slots.begin(); i != slots.end(); i++)
|
|
|
|
{
|
|
|
|
if((*i)->method == attrib)
|
|
|
|
{
|
|
|
|
AttributeDataPacket *adp =
|
|
|
|
(AttributeDataPacket *)(*i)->createPacket(1);
|
|
|
|
adp->add(value);
|
|
|
|
adp->send();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Object_skel::_generateSlots(const std::string& name,
|
|
|
|
const std::string& interface)
|
|
|
|
{
|
|
|
|
InterfaceDef d = _queryInterface(interface);
|
|
|
|
vector<string>::iterator ii;
|
|
|
|
for(ii = d.inheritedInterfaces.begin();
|
|
|
|
ii != d.inheritedInterfaces.end(); ii++)
|
|
|
|
{
|
|
|
|
if(_generateSlots(name, *ii)) return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<AttributeDef>::iterator ai;
|
|
|
|
for(ai = d.attributes.begin(); ai != d.attributes.end(); ai++)
|
|
|
|
{
|
|
|
|
if(ai->flags & attributeAttribute)
|
|
|
|
{
|
|
|
|
if((ai->flags & streamIn && ai->name == name)
|
|
|
|
|| (ai->flags & streamOut && ai->name+"_changed" == name))
|
|
|
|
{
|
|
|
|
_initAttribute(*ai);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object_skel::_QueryInitStreamFunc(Object_skel *skel, const
|
|
|
|
std::string& name)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* this function
|
|
|
|
*
|
|
|
|
* checks if there is a stream which should be added called <name>,
|
|
|
|
* and returns true if it in fact added a stream, so that requesting
|
|
|
|
* function needs to retry
|
|
|
|
*/
|
|
|
|
bool result = skel->_generateSlots(name, skel->_interfaceName());
|
|
|
|
if(!result)
|
|
|
|
{
|
|
|
|
arts_warning("used stream %s on object %s, which doesn't seem to exist",
|
|
|
|
name.c_str(), skel->_interfaceName().c_str());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Object: common for every object
|
|
|
|
*/
|
|
|
|
|
|
|
|
long Object_base::_staticObjectCount = 0;
|
|
|
|
|
|
|
|
Object_base::Object_base() : _deleteOk(false), _scheduleNode(0), _nextNotifyID(1),
|
|
|
|
_refCnt(1)
|
|
|
|
{
|
|
|
|
_internalData = new Arts::ObjectInternalData();
|
|
|
|
_internalData->stubForLocalObject = false;
|
|
|
|
_staticObjectCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_base::_destroy()
|
|
|
|
{
|
|
|
|
_deleteOk = true;
|
|
|
|
|
|
|
|
if(_scheduleNode && !_internalData->stubForLocalObject)
|
|
|
|
{
|
|
|
|
if(_scheduleNode->remoteScheduleNode())
|
|
|
|
{
|
|
|
|
delete _scheduleNode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FlowSystem_impl *fs = Dispatcher::the()->flowSystem();
|
|
|
|
assert(fs);
|
|
|
|
|
|
|
|
fs->removeObject(_scheduleNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_base::~Object_base()
|
|
|
|
{
|
|
|
|
if(!_deleteOk)
|
|
|
|
{
|
|
|
|
arts_fatal("reference counting violation - you may not call delete "
|
|
|
|
"manually - use _release() instead");
|
|
|
|
}
|
|
|
|
assert(_deleteOk);
|
|
|
|
|
|
|
|
/* remove attribute slots */
|
|
|
|
list<AttributeSlotBind *>::iterator ai;
|
|
|
|
for(ai = _internalData->attributeSlots.begin();
|
|
|
|
ai != _internalData->attributeSlots.end(); ai++)
|
|
|
|
{
|
|
|
|
delete (*ai);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clear stream list */
|
|
|
|
list<ObjectStreamInfo *>::iterator osii;
|
|
|
|
for(osii = _streamList.begin(); osii != _streamList.end(); osii++)
|
|
|
|
delete (*osii);
|
|
|
|
|
|
|
|
/* inform weak references that we don't exist any longer */
|
|
|
|
while(!_internalData->weakReferences.empty())
|
|
|
|
_internalData->weakReferences.front()->release();
|
|
|
|
|
|
|
|
/* inform notification manager that we don't exist any longer */
|
|
|
|
NotificationManager::the()->removeClient(this);
|
|
|
|
|
|
|
|
delete _internalData;
|
|
|
|
_staticObjectCount--;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScheduleNode *Object_base::_node()
|
|
|
|
{
|
|
|
|
if(!_scheduleNode)
|
|
|
|
{
|
|
|
|
switch(_location())
|
|
|
|
{
|
|
|
|
case objectIsLocal:
|
|
|
|
{
|
|
|
|
FlowSystem_impl *fs = Dispatcher::the()->flowSystem();
|
|
|
|
assert(fs);
|
|
|
|
_scheduleNode = fs->addObject(_skel());
|
|
|
|
|
|
|
|
/* init streams */
|
|
|
|
|
|
|
|
list<ObjectStreamInfo *>::iterator osii;
|
|
|
|
for(osii = _streamList.begin(); osii != _streamList.end(); osii++)
|
|
|
|
{
|
|
|
|
_scheduleNode->initStream((*osii)->name,(*osii)->ptr,(*osii)->flags);
|
|
|
|
}
|
|
|
|
_scheduleNode->initStream("QueryInitStreamFunc",
|
|
|
|
(void *)Object_skel::_QueryInitStreamFunc, -1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case objectIsRemote:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* if we're just a stub to an object that is local inside
|
|
|
|
* this process, then we don't create a new schedule node,
|
|
|
|
* but find the one associated with the implementation
|
|
|
|
*
|
|
|
|
* (this happens for instance for objects implemented as
|
|
|
|
* artsbuilder structures)
|
|
|
|
*/
|
|
|
|
if(_internalData->stubForLocalObject)
|
|
|
|
{
|
|
|
|
Dispatcher *disp = Dispatcher::the();
|
|
|
|
Object_skel *localObject;
|
|
|
|
|
|
|
|
localObject = disp->getLocalObject(_stub()->_objectID);
|
|
|
|
arts_assert(localObject);
|
|
|
|
|
|
|
|
_scheduleNode = localObject->_node();
|
|
|
|
localObject->_release();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_scheduleNode = new RemoteScheduleNode(_stub());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(_scheduleNode);
|
|
|
|
}
|
|
|
|
return _scheduleNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object_base::_isEqual(Object_base *object) const
|
|
|
|
{
|
|
|
|
return (_internalObjectID == object->_internalObjectID);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Object_base::_cast(unsigned long iid)
|
|
|
|
{
|
|
|
|
if(iid == Object_base::_IID) return (Object *)this;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *Object_base::_cast(const std::string& interface)
|
|
|
|
{
|
|
|
|
return _cast(MCOPUtils::makeIID(interface));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object_base::_error()
|
|
|
|
{
|
|
|
|
// no error as default ;)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_skel *Object_base::_skel()
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_stub *Object_base::_stub()
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_stub *Object_stub::_stub()
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_base::ObjectLocation Object_stub::_location() const
|
|
|
|
{
|
|
|
|
return objectIsRemote;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_skel *Object_skel::_skel()
|
|
|
|
{
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_base::ObjectLocation Object_skel::_location() const
|
|
|
|
{
|
|
|
|
return objectIsLocal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_initStream(const string& name, void *ptr, long flags)
|
|
|
|
{
|
|
|
|
ObjectStreamInfo *osi = new ObjectStreamInfo;
|
|
|
|
osi->name = name;
|
|
|
|
osi->ptr = ptr;
|
|
|
|
osi->flags = flags;
|
|
|
|
_streamList.push_back(osi);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_base::calculateBlock(unsigned long)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
string Object_base::_interfaceName()
|
|
|
|
{
|
|
|
|
assert(0); // derived classes *must* override this
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
Buffer *Object_base::_allocCustomMessage(long /*handlerID*/)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_base::_sendCustomMessage(Buffer *buffer)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
delete buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default I/O: nothing at this level, use child virtuals
|
|
|
|
vector<std::string> Object_base::_defaultPortsIn() const
|
|
|
|
{
|
|
|
|
vector<std::string> ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
vector<std::string> Object_base::_defaultPortsOut() const
|
|
|
|
{
|
|
|
|
vector<std::string> ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Weak References
|
|
|
|
|
|
|
|
void Object_base::_addWeakReference(WeakReferenceBase *b)
|
|
|
|
{
|
|
|
|
_internalData->weakReferences.push_back(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_base::_removeWeakReference(WeakReferenceBase *b)
|
|
|
|
{
|
|
|
|
_internalData->weakReferences.remove(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stuff for object skeletons
|
|
|
|
*/
|
|
|
|
|
|
|
|
Object_skel::Object_skel() :_remoteSendCount(0), _remoteSendUpdated(false)
|
|
|
|
{
|
|
|
|
_objectID = Dispatcher::the()->addObject(this);
|
|
|
|
_connection = Dispatcher::the()->loopbackConnection();
|
|
|
|
_internalData->methodTableInit = false;
|
|
|
|
|
|
|
|
/* big enough for our header + 0x + needed number of hex characters + ending NULL */
|
|
|
|
char ioid[7 + 2*sizeof(void *)+1];
|
|
|
|
sprintf(ioid,"SKEL:%p",(void *)this);
|
|
|
|
_internalObjectID = ioid;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_skel::~Object_skel()
|
|
|
|
{
|
|
|
|
Dispatcher::the()->removeObject(_objectID);
|
|
|
|
}
|
|
|
|
|
|
|
|
// flow system
|
|
|
|
|
|
|
|
FlowSystem Object_skel::_flowSystem()
|
|
|
|
{
|
|
|
|
FlowSystem_base *fs = Dispatcher::the()->flowSystem();
|
|
|
|
if(fs)
|
|
|
|
return FlowSystem::_from_base(fs->_copy());
|
|
|
|
else
|
|
|
|
return FlowSystem::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
// reference counting
|
|
|
|
|
|
|
|
void Object_skel::_release()
|
|
|
|
{
|
|
|
|
arts_return_if_fail(_refCnt > 0);
|
|
|
|
|
|
|
|
_refCnt--;
|
|
|
|
if(_refCnt == 0) _destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_copyRemote()
|
|
|
|
{
|
|
|
|
// cout << "_copyRemote();" << endl;
|
|
|
|
|
|
|
|
_copy();
|
|
|
|
_remoteSendCount++;
|
|
|
|
_remoteSendUpdated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_releaseRemote()
|
|
|
|
{
|
|
|
|
//cout << "_releaseRemote();" << endl;
|
|
|
|
|
|
|
|
Connection *conn = Dispatcher::the()->activeConnection();
|
|
|
|
list<Connection *>::iterator i;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
for(i=_remoteUsers.begin(); !found && i != _remoteUsers.end(); i++)
|
|
|
|
{
|
|
|
|
found = (*i) == conn;
|
|
|
|
if(found)
|
|
|
|
{
|
|
|
|
_remoteUsers.erase(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(found);
|
|
|
|
_release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_useRemote()
|
|
|
|
{
|
|
|
|
//cout << "_useRemote();" << endl;
|
|
|
|
|
|
|
|
Connection *conn = Dispatcher::the()->activeConnection();
|
|
|
|
if(_remoteSendCount == 0)
|
|
|
|
{
|
|
|
|
arts_warning("_useRemote without prior _copyRemote() - this might fail sometimes");
|
|
|
|
_copyRemote();
|
|
|
|
}
|
|
|
|
|
|
|
|
_remoteSendCount--;
|
|
|
|
_remoteUsers.push_back(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is needed when we've received an object from wire which we now
|
|
|
|
* hold locally. Of course it has been _copyRemote()d (rightly so), but
|
|
|
|
* we will not use it remotely, so we need to cancel the _copyRemote().
|
|
|
|
*
|
|
|
|
* Added to _base due to BC.
|
|
|
|
*/
|
|
|
|
void Object_base::_cancelCopyRemote()
|
|
|
|
{
|
|
|
|
assert(_location() == objectIsLocal);
|
|
|
|
|
|
|
|
if(_skel()->_remoteSendCount == 0)
|
|
|
|
{
|
|
|
|
arts_warning("_cancelCopyRemote without prior _copyRemote() - this might fail sometimes");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_skel()->_remoteSendCount--;
|
|
|
|
_release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_disconnectRemote(Connection *conn)
|
|
|
|
{
|
|
|
|
//cout << "_disconnectRemote();" << endl;
|
|
|
|
|
|
|
|
int rcount = 0;
|
|
|
|
list<Connection *>::iterator i;
|
|
|
|
|
|
|
|
i=_remoteUsers.begin();
|
|
|
|
while(i != _remoteUsers.end())
|
|
|
|
{
|
|
|
|
if((*i) == conn)
|
|
|
|
{
|
|
|
|
_remoteUsers.erase(i);
|
|
|
|
i = _remoteUsers.begin();
|
|
|
|
rcount++;
|
|
|
|
}
|
|
|
|
else i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(rcount) {
|
|
|
|
arts_debug("client disconnected: dropped one object reference");
|
|
|
|
rcount--;
|
|
|
|
_release();
|
|
|
|
}
|
|
|
|
/* warning: object may not exist any longer here */
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_referenceClean()
|
|
|
|
{
|
|
|
|
if(_remoteSendCount > 0)
|
|
|
|
{
|
|
|
|
if(_remoteSendUpdated)
|
|
|
|
{
|
|
|
|
// this ensures that every client gets at least five
|
|
|
|
// seconds to connect
|
|
|
|
_remoteSendUpdated = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int rcount = _remoteSendCount;
|
|
|
|
|
|
|
|
arts_debug("_referenceClean: found unused object marked by "
|
|
|
|
"_copyRemote => releasing");
|
|
|
|
|
|
|
|
while(rcount--)
|
|
|
|
{
|
|
|
|
_remoteSendCount--;
|
|
|
|
_release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* warning: object may be gone here */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string Object_skel::_toString()
|
|
|
|
{
|
|
|
|
return Dispatcher::the()->objectToString(_objectID);
|
|
|
|
}
|
|
|
|
|
|
|
|
string Object_skel::_interfaceName()
|
|
|
|
{
|
|
|
|
assert(0); // derived classes *must* override this
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
string Object_skel::_interfaceNameSkel()
|
|
|
|
{
|
|
|
|
// derived classes *must* override this, but we return a sane value here
|
|
|
|
// anyway, because DynamicSkeleton depends on this
|
|
|
|
return "Arts::Object";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object_skel::_isCompatibleWith(const std::string& interfacename)
|
|
|
|
{
|
|
|
|
if (interfacename=="Arts::Object") return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterfaceDef Object_skel::_queryInterface(const string& name)
|
|
|
|
{
|
|
|
|
return Dispatcher::the()->interfaceRepo().queryInterface(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeDef Object_skel::_queryType(const string& name)
|
|
|
|
{
|
|
|
|
return Dispatcher::the()->interfaceRepo().queryType(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
EnumDef Object_skel::_queryEnum(const string& name)
|
|
|
|
{
|
|
|
|
return Dispatcher::the()->interfaceRepo().queryEnum(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Aggregation
|
|
|
|
std::string Object_skel::_addChild(Arts::Object child, const std::string& name)
|
|
|
|
{
|
|
|
|
return _internalData->children.put(name,child);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Object_skel::_removeChild(const std::string& name)
|
|
|
|
{
|
|
|
|
return _internalData->children.remove(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
Arts::Object Object_skel::_getChild(const std::string& name)
|
|
|
|
{
|
|
|
|
Arts::Object result;
|
|
|
|
if(_internalData->children.get(name,result))
|
|
|
|
return result;
|
|
|
|
else
|
|
|
|
return Arts::Object::null();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> *Object_skel::_queryChildren()
|
|
|
|
{
|
|
|
|
return _internalData->children.contents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_addMethod(DispatchFunction disp, void *obj,
|
|
|
|
const MethodDef& md)
|
|
|
|
{
|
|
|
|
Arts::ObjectInternalData::MethodTableEntry me;
|
|
|
|
me.dispFunc.dispatcher = disp;
|
|
|
|
me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfNormal;
|
|
|
|
me.object = obj;
|
|
|
|
me.methodDef = md;
|
|
|
|
_internalData->methodTable.push_back(me);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_addMethod(OnewayDispatchFunction disp, void *obj,
|
|
|
|
const MethodDef& md)
|
|
|
|
{
|
|
|
|
Arts::ObjectInternalData::MethodTableEntry me;
|
|
|
|
me.dispFunc.onewayDispatcher = disp;
|
|
|
|
me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfOneway;
|
|
|
|
me.object = obj;
|
|
|
|
me.methodDef = md;
|
|
|
|
_internalData->methodTable.push_back(me);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_addMethod(DynamicDispatchFunction disp, void *obj,
|
|
|
|
const MethodDef& md)
|
|
|
|
{
|
|
|
|
Arts::ObjectInternalData::MethodTableEntry me;
|
|
|
|
me.dispFunc.dynamicDispatcher = disp;
|
|
|
|
me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfDynamic;
|
|
|
|
me.object = obj;
|
|
|
|
me.methodDef = md;
|
|
|
|
_internalData->methodTable.push_back(me);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
long Object_skel::_addCustomMessageHandler(OnewayDispatchFunction handler,
|
|
|
|
void *obj)
|
|
|
|
{
|
|
|
|
if(!_internalData->methodTableInit)
|
|
|
|
{
|
|
|
|
// take care that the object base methods are at the beginning
|
|
|
|
Object_skel::_buildMethodTable();
|
|
|
|
_buildMethodTable();
|
|
|
|
_internalData->methodTableInit = true;
|
|
|
|
}
|
|
|
|
Arts::ObjectInternalData::MethodTableEntry me;
|
|
|
|
me.dispFunc.onewayDispatcher = handler;
|
|
|
|
me.dispatchStyle = ObjectInternalData::MethodTableEntry::dfOneway;
|
|
|
|
me.object = obj;
|
|
|
|
me.methodDef.name = "_userdefined_customdatahandler";
|
|
|
|
_internalData->methodTable.push_back(me);
|
|
|
|
return _internalData->methodTable.size()-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_dispatch(Buffer *request, Buffer *result,long methodID)
|
|
|
|
{
|
|
|
|
if(!_internalData->methodTableInit)
|
|
|
|
{
|
|
|
|
// take care that the object base methods are at the beginning
|
|
|
|
Object_skel::_buildMethodTable();
|
|
|
|
_buildMethodTable();
|
|
|
|
_internalData->methodTableInit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ObjectInternalData::MethodTableEntry& me
|
|
|
|
= _internalData->methodTable[methodID];
|
|
|
|
|
|
|
|
if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfNormal)
|
|
|
|
me.dispFunc.dispatcher(me.object, request, result);
|
|
|
|
else if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfDynamic)
|
|
|
|
me.dispFunc.dynamicDispatcher(me.object, methodID, request, result);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arts_assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Object_skel::_dispatch(Buffer *request,long methodID)
|
|
|
|
{
|
|
|
|
if(!_internalData->methodTableInit)
|
|
|
|
{
|
|
|
|
// take care that the object base methods are at the beginning
|
|
|
|
Object_skel::_buildMethodTable();
|
|
|
|
_buildMethodTable();
|
|
|
|
_internalData->methodTableInit = true;
|
|
|
|
}
|
|
|
|
const ObjectInternalData::MethodTableEntry& me
|
|
|
|
= _internalData->methodTable[methodID];
|
|
|
|
|
|
|
|
if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfOneway)
|
|
|
|
me.dispFunc.onewayDispatcher(me.object, request);
|
|
|
|
else if(me.dispatchStyle == ObjectInternalData::MethodTableEntry::dfDynamic)
|
|
|
|
me.dispFunc.dynamicDispatcher(me.object, methodID, request, 0);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
arts_assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
long Object_skel::_lookupMethod(const MethodDef& md)
|
|
|
|
{
|
|
|
|
long mcount = 0;
|
|
|
|
|
|
|
|
if(!_internalData->methodTableInit)
|
|
|
|
{
|
|
|
|
// take care that the object base methods are at the beginning
|
|
|
|
Object_skel::_buildMethodTable();
|
|
|
|
_buildMethodTable();
|
|
|
|
_internalData->methodTableInit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<Arts::ObjectInternalData::MethodTableEntry>::iterator i;
|
|
|
|
for(i=_internalData->methodTable.begin(); i != _internalData->methodTable.end(); i++)
|
|
|
|
{
|
|
|
|
MethodDef& mdm = i->methodDef;
|
|
|
|
if(mdm.name == md.name && mdm.type == md.type)
|
|
|
|
{
|
|
|
|
/* TODO: compare signature
|
|
|
|
vector<ParamDef *>::const_iterator j,k;
|
|
|
|
j = md.signature.begin();
|
|
|
|
k = mdm.signature.begin();
|
|
|
|
while(j != md.signature.end() && (*j) == (*k))
|
|
|
|
{
|
|
|
|
j++;
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(j == md.signature.end() && k == mdm.signature.end())
|
|
|
|
*/
|
|
|
|
return mcount;
|
|
|
|
}
|
|
|
|
mcount++;
|
|
|
|
}
|
|
|
|
arts_warning("_lookupMethod %s %s failed this might be caused by "
|
|
|
|
"incompatible IDL files and is likely to result in crashes",
|
|
|
|
md.type.c_str(),md.name.c_str());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MethodDef& Object_skel::_dsGetMethodDef(long methodID)
|
|
|
|
{
|
|
|
|
if(!_internalData->methodTableInit)
|
|
|
|
{
|
|
|
|
// take care that the object base methods are at the beginning
|
|
|
|
Object_skel::_buildMethodTable();
|
|
|
|
_buildMethodTable();
|
|
|
|
_internalData->methodTableInit = true;
|
|
|
|
}
|
|
|
|
return _internalData->methodTable[methodID].methodDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
// _lookupMethod
|
|
|
|
static void _dispatch_Arts_Object_00(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
Arts::MethodDef methodDef(*request);
|
|
|
|
result->writeLong(((Arts::Object_skel *)object)->_lookupMethod(methodDef));
|
|
|
|
}
|
|
|
|
|
|
|
|
// _interfaceName
|
|
|
|
static void _dispatch_Arts_Object_01(void *object, Arts::Buffer *, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
result->writeString(((Arts::Object_skel *)object)->_interfaceName());
|
|
|
|
}
|
|
|
|
|
|
|
|
// _queryInterface
|
|
|
|
static void _dispatch_Arts_Object_02(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
request->readString(name);
|
|
|
|
Arts::InterfaceDef _returnCode = ((Arts::Object_skel *)object)->_queryInterface(name);
|
|
|
|
_returnCode.writeType(*result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// _queryType
|
|
|
|
static void _dispatch_Arts_Object_03(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
request->readString(name);
|
|
|
|
Arts::TypeDef _returnCode = ((Arts::Object_skel *)object)->_queryType(name);
|
|
|
|
_returnCode.writeType(*result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// _queryEnum
|
|
|
|
static void _dispatch_Arts_Object_04(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
request->readString(name);
|
|
|
|
Arts::EnumDef _returnCode = ((Arts::Object_skel *)object)->_queryEnum(name);
|
|
|
|
_returnCode.writeType(*result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// _toString
|
|
|
|
static void _dispatch_Arts_Object_05(void *object, Arts::Buffer *, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
result->writeString(((Arts::Object_skel *)object)->_toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
// _isCompatibleWith
|
|
|
|
static void _dispatch_Arts_Object_06(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::string interfacename;
|
|
|
|
request->readString(interfacename);
|
|
|
|
result->writeBool(((Arts::Object_skel *)object)->_isCompatibleWith(interfacename));
|
|
|
|
}
|
|
|
|
|
|
|
|
// _copyRemote
|
|
|
|
static void _dispatch_Arts_Object_07(void *object, Arts::Buffer *, Arts::Buffer *)
|
|
|
|
{
|
|
|
|
((Arts::Object_skel *)object)->_copyRemote();
|
|
|
|
}
|
|
|
|
|
|
|
|
// _useRemote
|
|
|
|
static void _dispatch_Arts_Object_08(void *object, Arts::Buffer *, Arts::Buffer *)
|
|
|
|
{
|
|
|
|
((Arts::Object_skel *)object)->_useRemote();
|
|
|
|
}
|
|
|
|
|
|
|
|
// _releaseRemote
|
|
|
|
static void _dispatch_Arts_Object_09(void *object, Arts::Buffer *, Arts::Buffer *)
|
|
|
|
{
|
|
|
|
((Arts::Object_skel *)object)->_releaseRemote();
|
|
|
|
}
|
|
|
|
|
|
|
|
// _addChild
|
|
|
|
static void _dispatch_Arts_Object_10(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
Arts::Object_base* _temp_child;
|
|
|
|
readObject(*request,_temp_child);
|
|
|
|
Arts::Object child = Arts::Object::_from_base(_temp_child);
|
|
|
|
std::string name;
|
|
|
|
request->readString(name);
|
|
|
|
result->writeString(((Arts::Object_skel *)object)->_addChild(child,name));
|
|
|
|
}
|
|
|
|
|
|
|
|
// _removeChild
|
|
|
|
static void _dispatch_Arts_Object_11(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
request->readString(name);
|
|
|
|
result->writeBool(((Arts::Object_skel *)object)->_removeChild(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
// _getChild
|
|
|
|
static void _dispatch_Arts_Object_12(void *object, Arts::Buffer *request, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
request->readString(name);
|
|
|
|
Arts::Object returnCode = ((Arts::Object_skel *)object)->_getChild(name);
|
|
|
|
writeObject(*result,returnCode._base());
|
|
|
|
}
|
|
|
|
|
|
|
|
// _queryChildren
|
|
|
|
static void _dispatch_Arts_Object_13(void *object, Arts::Buffer *, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
std::vector<std::string> *_returnCode = ((Arts::Object_skel *)object)->_queryChildren();
|
|
|
|
result->writeStringSeq(*_returnCode);
|
|
|
|
delete _returnCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
// _get__flowSystem
|
|
|
|
static void _dispatch_Arts_Object_14(void *object, Arts::Buffer *, Arts::Buffer *result)
|
|
|
|
{
|
|
|
|
Arts::FlowSystem returnCode = ((Arts::Object_skel *)object)->_flowSystem();
|
|
|
|
writeObject(*result,returnCode._base());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Arts::Object_skel::_buildMethodTable()
|
|
|
|
{
|
|
|
|
Arts::Buffer m;
|
|
|
|
m.fromString(
|
|
|
|
"MethodTable:0000000e5f6c6f6f6b75704d6574686f6400000000056c6f6e6700"
|
|
|
|
"000000020000000100000010417274733a3a4d6574686f64446566000000000a6d"
|
|
|
|
"6574686f644465660000000000000000000000000f5f696e746572666163654e61"
|
|
|
|
"6d650000000007737472696e6700000000020000000000000000000000105f7175"
|
|
|
|
"657279496e746572666163650000000013417274733a3a496e7465726661636544"
|
|
|
|
"656600000000020000000100000007737472696e6700000000056e616d65000000"
|
|
|
|
"0000000000000000000b5f717565727954797065000000000e417274733a3a5479"
|
|
|
|
"706544656600000000020000000100000007737472696e6700000000056e616d65"
|
|
|
|
"0000000000000000000000000b5f7175657279456e756d000000000e417274733a"
|
|
|
|
"3a456e756d44656600000000020000000100000007737472696e6700000000056e"
|
|
|
|
"616d650000000000000000000000000a5f746f537472696e670000000007737472"
|
|
|
|
"696e6700000000020000000000000000000000125f6973436f6d70617469626c65"
|
|
|
|
"576974680000000008626f6f6c65616e0000000002000000010000000773747269"
|
|
|
|
"6e67000000000e696e746572666163656e616d650000000000000000000000000c"
|
|
|
|
"5f636f707952656d6f74650000000005766f696400000000020000000000000000"
|
|
|
|
"0000000b5f75736552656d6f74650000000005766f696400000000020000000000"
|
|
|
|
"0000000000000f5f72656c6561736552656d6f74650000000005766f6964000000"
|
|
|
|
"000200000000000000000000000a5f6164644368696c640000000007737472696e"
|
|
|
|
"67000000000200000002000000076f626a65637400000000066368696c64000000"
|
|
|
|
"000000000007737472696e6700000000056e616d65000000000000000000000000"
|
|
|
|
"0d5f72656d6f76654368696c640000000008626f6f6c65616e0000000002000000"
|
|
|
|
"0100000007737472696e6700000000056e616d650000000000000000000000000a"
|
|
|
|
"5f6765744368696c6400000000076f626a65637400000000020000000100000007"
|
|
|
|
"737472696e6700000000056e616d650000000000000000000000000f5f71756572"
|
|
|
|
"794368696c6472656e00000000082a737472696e67000000000200000000000000"
|
|
|
|
"00000000115f6765745f5f666c6f7753797374656d0000000011417274733a3a46"
|
|
|
|
"6c6f7753797374656d00000000020000000000000000",
|
|
|
|
"MethodTable"
|
|
|
|
);
|
|
|
|
_addMethod(_dispatch_Arts_Object_00,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_01,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_02,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_03,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_04,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_05,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_06,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_07,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_08,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_09,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_10,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_11,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_12,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_13,this,Arts::MethodDef(m));
|
|
|
|
_addMethod(_dispatch_Arts_Object_14,this,Arts::MethodDef(m));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stuff for object stubs
|
|
|
|
*/
|
|
|
|
|
|
|
|
Object_stub::Object_stub()
|
|
|
|
{
|
|
|
|
assert(0); // never use this constructor, as it doesn't assign an object ID
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_stub::Object_stub(Connection *connection, long objectID)
|
|
|
|
{
|
|
|
|
_connection = connection;
|
|
|
|
_connection->_copy();
|
|
|
|
_objectID = objectID;
|
|
|
|
_lookupCacheRandom = rand();
|
|
|
|
|
|
|
|
if(_connection == Dispatcher::the()->loopbackConnection())
|
|
|
|
_internalData->stubForLocalObject = true;
|
|
|
|
|
|
|
|
char ioid[128];
|
|
|
|
sprintf(ioid,"STUB:%ld:%p",_objectID,(void *)connection);
|
|
|
|
_internalObjectID = ioid;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object_stub::~Object_stub()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|