/* 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. */ #ifndef OBJECT_H #define OBJECT_H #include "buffer.h" #include "connection.h" #include "notification.h" #include #include #include #include "arts_export.h" /* * BC - tqStatus (2002-03-08): Object_base, Object_skel, Object_stub * * All of them have to be kept binary compatible carefully, due to interaction * with generated code. There are d ptrs in _skel and _stub, NOT TO BE USED * NORMALLY. Normally, do use _internalData instead, as this is much faster * than creating two d objects per MCOP implementation/stub. Handle with care. */ namespace Arts { /* custom dispatching functions */ typedef void (*DispatchFunction)(void *object, Buffer *request, Buffer *result); typedef void (*OnewayDispatchFunction)(void *object, Buffer *request); typedef void (*DynamicDispatchFunction)(void *object, long methodID, Buffer *request, Buffer *result); class ScheduleNode; class Object_skel; class Object_stub; class FlowSystem; class MethodDef; class ObjectReference; class WeakReferenceBase; class Object; class ObjectManager; class DynamicSkeletonData; class DynamicSkeletonBase; class ARTS_EXPORT Object_base : public NotificationClient { private: friend class DynamicRequest; friend class ObjectManager; bool _deleteOk; // ensure that "delete" is not called manually protected: /** * ObjectInternalData tqcontains private data structures for * - Object_base * - Object_stub * - Object_skel * * This is an optimization over adding each of them private data pointers, * which would lead to some more bloat. */ class ObjectInternalData *_internalData; struct ObjectStreamInfo; Object_base(); virtual ~Object_base(); /* * internal management for streams */ ScheduleNode *_scheduleNode; std::list _streamList; virtual Object_skel *_skel(); virtual Object_stub *_stub(); enum ObjectLocation { objectIsLocal, objectIsRemote }; virtual ObjectLocation _location() const = 0; long _objectID; Connection *_connection; std::string _internalObjectID; // two objects are "_isEqual" when these match long _nextNotifyID; long _refCnt; // reference count static long _staticObjectCount; void _destroy(); // use this instead of delete (takes care of // properly removing flow system node) public: static unsigned long _IID; // interface ID /** * custom messaging: these can be used to send a custom data to other * objects. Warning: these are *not* usable for local objects. You may * only use these functions if you know that you are talking to a remote * object. Use _allocCustomMessage to allocate a message. Put the data * you want to send in the Buffer. After that, call _sendCustomMessage. * Don't free the buffer - this will happen automatically. */ virtual Buffer *_allocCustomMessage(long handlerID); virtual void _sendCustomMessage(Buffer *data); /* * generic capabilities, which allow find out what you can do with an * object even if you don't know it's interface */ virtual long _lookupMethod(const Arts::MethodDef &) = 0; virtual std::string _interfaceName() = 0; virtual class InterfaceDef _queryInterface(const std::string& name) = 0; virtual class TypeDef _queryType(const std::string& name) = 0; virtual class EnumDef _queryEnum(const std::string& name) = 0; virtual std::string _toString() = 0; /* * stuff for streaming (put in a seperate interface?) */ virtual void calculateBlock(unsigned long cycles); ScheduleNode *_node(); virtual FlowSystem _flowSystem() = 0; /* * reference counting */ virtual void _release() = 0; virtual void _copyRemote() = 0; virtual void _useRemote() = 0; virtual void _releaseRemote() = 0; // BC issue: added _cancelCopyRemote here to avoid virtual function void _cancelCopyRemote(); void _addWeakReference(WeakReferenceBase *reference); void _removeWeakReference(WeakReferenceBase *reference); inline Object_base *_copy() { assert(_refCnt > 0); _refCnt++; return this; } // Default I/O info virtual std::vector _defaultPortsIn() const; virtual std::vector _defaultPortsOut() const; // cast operation virtual void *_cast(unsigned long iid); void *_cast(const std::string& interface); // Run-time type compatibility check virtual bool _isCompatibleWith(const std::string& interfacename) = 0; // Aggregation virtual std::string _addChild(Arts::Object child, const std::string& name) = 0; virtual bool _removeChild(const std::string& name) = 0; virtual Arts::Object _getChild(const std::string& name) = 0; virtual std::vector * _queryChildren() = 0; /* * when this is true, a fatal communication error has occurred (of course * only possible for remote objects) - maybe your returncode is invalid, * maybe your last invocation didn't succeed... */ virtual bool _error(); inline static long _objectCount() { return _staticObjectCount; } inline long _mkNotifyID() { return _nextNotifyID++; } // object creation static Object_base *_create(const std::string& subClass = "Object"); // comparison bool _isEqual(Object_base *object) const; // static converter (from reference) static Object_base *_fromString(const std::string& objectref); static Object_base *_fromReference(class ObjectReference ref, bool needcopy); }; /* * Dispatching */ class Buffer; class MethodDef; class Object_skel_private; class AnyConstRef; class AttributeDef; class ARTS_EXPORT Object_skel : virtual public Object_base { private: friend class Object_base; friend class DynamicSkeletonData; friend class DynamicSkeletonBase; Object_skel_private *_d_skel;// do not use until there is a very big problem // reference counting - remote object watching long _remoteSendCount; // don't kill objects just sent to other server bool _remoteSendUpdated; // timeout if they don't want the object std::list _remoteUsers; // who is using it? protected: void _addMethod(DispatchFunction disp, void *object, const MethodDef& md); void _addMethod(OnewayDispatchFunction disp, void *object, const MethodDef& md); void _addMethod(DynamicDispatchFunction disp, void *object, const MethodDef& md); void _initStream(const std::string& name, void *ptr, long flags); /** stuff relative to attribute notifications **/ bool _initAttribute(const Arts::AttributeDef& attribute); static bool _QueryInitStreamFunc(Object_skel *skel,const std::string& name); bool _generateSlots(const std::string& name, const std::string& interface); /** for DynamicSkeleton: **/ const MethodDef& _dsGetMethodDef(long methodID); protected: void _defaultNotify(const Notification& notification); void notify(const Notification& notification); void _emit_changed(const char *stream, const AnyConstRef& value); /** * custom messaging: this is used to install a custom data handler that * can be used to receive non-standard messages */ long _addCustomMessageHandler(OnewayDispatchFunction handler, void *object); Object_skel *_skel(); ObjectLocation _location() const; public: Object_skel(); virtual ~Object_skel(); // reference counting connection drop void _disconnectRemote(class Connection *connection); void _referenceClean(); // synchronous & asynchronous dispatching void _dispatch(Buffer *request, Buffer *result,long methodID); void _dispatch(Buffer *request, long methodID); long _lookupMethod(const MethodDef &); /* * standard interface for every object skeleton */ static std::string _interfaceNameSkel(); virtual void _buildMethodTable(); /* * reference counting */ virtual void _release(); virtual void _copyRemote(); virtual void _useRemote(); virtual void _releaseRemote(); /* * streaming */ FlowSystem _flowSystem(); /* * to inspect the (remote) object interface */ virtual std::string _interfaceName(); InterfaceDef _queryInterface(const std::string& name); TypeDef _queryType(const std::string& name); EnumDef _queryEnum(const std::string& name); virtual std::string _toString(); // Run-time type compatibility check bool _isCompatibleWith(const std::string& interfacename); // Aggregation std::string _addChild(Arts::Object child, const std::string& name); bool _removeChild(const std::string& name); Arts::Object _getChild(const std::string& name); std::vector * _queryChildren(); }; class Object_stub_private; class ARTS_EXPORT Object_stub : virtual public Object_base { private: friend class Object_base; Object_stub_private *_d_stub;// do not use until there is a very big problem protected: long _lookupCacheRandom; Object_stub(); Object_stub(Connection *connection, long objectID); virtual ~Object_stub(); virtual Object_stub *_stub(); ObjectLocation _location() const; enum { _lookupMethodCacheSize = 337 }; static struct methodCacheEntry { methodCacheEntry() : obj(NULL),method(NULL),ID(0) {} ; Object_stub *obj; const char *method; long ID; } *_lookupMethodCache; long _lookupMethodFast(const char *method); long _lookupMethod(const MethodDef &); public: /* * custom messaging */ Buffer *_allocCustomMessage(long handlerID); void _sendCustomMessage(Buffer *data); /* * to inspect the (remote) object interface */ std::string _interfaceName(); InterfaceDef _queryInterface(const std::string& name); TypeDef _queryType(const std::string& name); EnumDef _queryEnum(const std::string& name); std::string _toString(); /* * streaming */ FlowSystem _flowSystem(); /* * reference counting */ virtual void _release(); virtual void _copyRemote(); virtual void _useRemote(); virtual void _releaseRemote(); // Run-time type compatibility check bool _isCompatibleWith(const std::string& interfacename); // Aggregation std::string _addChild(Arts::Object child, const std::string& name); bool _removeChild(const std::string& name); Arts::Object _getChild(const std::string& name); std::vector * _queryChildren(); /* * communication error? this is true when your connection to the remote * object is lost (e.g. when the remote server crashed) - your return * values are then undefined, so check this before relying too much * on some invocation */ bool _error(); /* * global cleanup */ static void _cleanupMethodCache(); }; } #endif