2009-01-04 15:21:04 +01:00
|
|
|
/*
|
|
|
|
|
INTERFACEPROXY - definition of forwarding proxies for the facade interfaces
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
2010-12-17 23:28:49 +01:00
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
This program 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 General Public License for more details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @file interfaceproxy.hpp
|
2018-04-03 06:28:29 +02:00
|
|
|
** Implementation of C++ binding proxies on top of the (plain-C based) interface system.
|
|
|
|
|
** This is an implementation facility within the application core, which allows to embody
|
|
|
|
|
** just an ["interface instance handle"](\ref instancehandle.hpp) into the implementation
|
|
|
|
|
** os some service, in order to get RAII-style registration of interfaces and loading of
|
|
|
|
|
** plug-ins.
|
|
|
|
|
**
|
|
|
|
|
** A *crucial requirement* for this approach to work is that any relevant interface
|
|
|
|
|
** to be bound and exposed as C++ object needs to set up a concrete specialisation of
|
|
|
|
|
** lumiera::facade::Proxy to drive instantiation of the actual binding proxy.
|
|
|
|
|
** The result of this setup is that clients can just invoke `SomeInterface::facade()`
|
|
|
|
|
** and thus call through proper C++ bindings with type safety and automatic
|
|
|
|
|
** lifecycle management.
|
|
|
|
|
**
|
|
|
|
|
** # Interface, Plug-in, Facade interface, Instance Handle and Proxy
|
|
|
|
|
**
|
|
|
|
|
** These are all terms related to the Interface- and Plug-in system for Lumiera.
|
|
|
|
|
** Communication between the Layers within the architecture is usually routed through
|
|
|
|
|
** *Layer Separation Interfaces*. Here we have to distinguish two different flavours
|
|
|
|
|
** of an "interface"
|
|
|
|
|
** - A Façade interface is written in C++ and is what you's usually
|
|
|
|
|
** denote with the term "interface": it defines a contract in terms of
|
|
|
|
|
** some abstract entities, without exposing implementation details.
|
|
|
|
|
** Ideally, the interface holds all you need to use a given service.
|
|
|
|
|
** - A C Language interface defined with the help of the Interface/Plugin system.
|
|
|
|
|
** It is a collection of functions and supports only the primitive types of the
|
|
|
|
|
** bare C Language. Objects need to be emulated by pointers to a struct type,
|
|
|
|
|
** and functors must be represented as static function pointers. In many cases
|
|
|
|
|
** you need to fall back to untyped `void*` unfortunately.
|
|
|
|
|
**
|
|
|
|
|
** @todo 2018 as it stands (since 2008), the Interface/Plug-in system fulfils the basic task
|
|
|
|
|
** it was created for, but is rather cumbersome to use in practice. We should investigate
|
|
|
|
|
** to use SWIG or something similar to generate the bindings and the low-level interfaces.
|
|
|
|
|
**
|
|
|
|
|
** The Interface/Plug-in system offers two basic usage scenarios
|
|
|
|
|
** - a CL-Interface can be published (from the service provider side).
|
|
|
|
|
** From that point on, clients can "open" that interface and talk to it.
|
|
|
|
|
** - a _client_ can use the CL-Interface of a Plug-in to _load_ a plug-in instance.
|
|
|
|
|
** From that point on, clients can talk through a interface handle to the plug-in.
|
|
|
|
|
**
|
|
|
|
|
** An Attempt was made to simplify and unify this process with the help of an InstanceHandle.
|
|
|
|
|
** This is an RAII-style handle object, which automates the registration and instance management.
|
|
|
|
|
**
|
|
|
|
|
** But in order to be able to actually access some service via a high-level façade interface,
|
|
|
|
|
** we still need a way to get a callable instance of the façade interface. This is where the
|
|
|
|
|
** proxy implementation comes into play. The binding proxy implements the façade and maps each
|
|
|
|
|
** high-level call into an invocation of the corresponding low-level function on the CL-interface.
|
|
|
|
|
**
|
|
|
|
|
** Whenever InstanceHandle was created with a second template parameter defining a façade interface,
|
|
|
|
|
** it automatically attempts to instantiate a lumiera::facade::Proxy templated to the actual type
|
|
|
|
|
** of the InstanceHandle. This proxy instance is then exposed via `lib::Depend<FacadeInterface>`
|
|
|
|
|
** This way, any call will be routed through the corresponding C Language function defined within
|
|
|
|
|
** the Interface/Plugin system. Moreover, there will be another subclass of the Facade interface
|
|
|
|
|
** sitting "on the other side" of the interface barrier to _actually implement_ the functionality.
|
|
|
|
|
**
|
|
|
|
|
** As a convention, each façade interface should hold a static accessor member named "facade" of
|
|
|
|
|
** type `lib::Depend<FacadeInterface>`, so client code can write e.g. `XYZInterface::facade()`
|
2016-11-04 22:29:24 +01:00
|
|
|
** to yield a reference to a proxy object implementing `XYZInterface`.
|
2009-01-04 15:21:04 +01:00
|
|
|
**
|
2018-04-03 06:28:29 +02:00
|
|
|
**
|
2016-11-04 22:29:24 +01:00
|
|
|
** # Interface Lifecycle
|
2009-01-04 15:21:04 +01:00
|
|
|
**
|
|
|
|
|
** Instances of an Interface are either directly provided by some facility within the core,
|
|
|
|
|
** or they are loaded from a shared module (plugin). In either case this means the interface
|
|
|
|
|
** isn't accessible all the time, rather it comes up at a defined point in the application
|
|
|
|
|
** lifecycle and similarly will be shut down deliberately at some point. Beyond this time
|
2018-04-03 06:28:29 +02:00
|
|
|
** window of availability, any access through the proxy factory throws an lumiera::error::Fatal.
|
2009-01-07 12:26:44 +01:00
|
|
|
** Any sort of dependency management is outside the scope of the InstanceHandle (for the core
|
2009-01-04 15:21:04 +01:00
|
|
|
** services, it is handled by the dependency of subsystems, while the plugin loader cares
|
|
|
|
|
** for dependency issues regarding loadable modules, thereby building on the deployment
|
2011-06-13 20:07:30 +02:00
|
|
|
** descriptors.)
|
2009-01-04 15:21:04 +01:00
|
|
|
**
|
|
|
|
|
** For the Layer separation interfaces, the process of loading and opening is abstracted as
|
2018-04-03 06:28:29 +02:00
|
|
|
** an InstanceHandle object. A service exposing an interface defines an InstanceHandle
|
|
|
|
|
** member using the appropriate template and ctor parameters; this causes registration with
|
|
|
|
|
** the Interface/Plugin and instantiates the corresponding facade::Proxy, which is then
|
|
|
|
|
** exposed through the lib::Depend front-end. Similarly, when the service implementation
|
|
|
|
|
** object is destroyed, the InstanceHandle goes out of scope, thereby detaching from the
|
|
|
|
|
** Interface/Proxy and deregistering and destroying the proxy object. Any further
|
|
|
|
|
** access beyond that point will raise an exception.
|
2018-04-03 03:14:55 +02:00
|
|
|
**
|
2018-04-03 06:28:29 +02:00
|
|
|
** # Usage
|
|
|
|
|
**
|
|
|
|
|
** While client code just includes the interface header (including lib/depend.hpp),
|
|
|
|
|
** there needs to be an actual implementation of each proxy object located in some translation
|
|
|
|
|
** unit, linked into the application core or `liblumieracommon.so`. This translation unit
|
|
|
|
|
** needs to specialise lumiera::facade::Proxy and then create an instance of that template.
|
|
|
|
|
** And, most importantly, such translation units (and _only such translation units_) must
|
|
|
|
|
** include this header `interfaceproxy.hpp` -- because it defines the concrete ctor
|
|
|
|
|
** and dtor of the facade::Link template and thus creates the missing "link" between
|
|
|
|
|
** the InstanceHandle and the actual proxy instantiation.
|
|
|
|
|
**
|
|
|
|
|
** @see instancehandle.hpp
|
|
|
|
|
** @see gui-notification-facade.h usage example (facade interface)
|
|
|
|
|
** @see notification-service.hpp
|
|
|
|
|
** @see notification-service.cpp (service implementation)
|
|
|
|
|
** @see notification-interface-proxy.cpp
|
2009-01-04 15:21:04 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LUMIERA_INTERFACE_PROXY_H
|
|
|
|
|
#define LUMIERA_INTERFACE_PROXY_H
|
|
|
|
|
|
|
|
|
|
|
2018-04-03 03:14:55 +02:00
|
|
|
#include "common/instancehandle.hpp"
|
2018-04-03 04:58:22 +02:00
|
|
|
#include "lib/error.hpp"
|
|
|
|
|
#include "lib/util.hpp"
|
2009-01-04 15:21:04 +01:00
|
|
|
|
2018-04-03 04:58:22 +02:00
|
|
|
using util::cStr;
|
2009-01-04 15:21:04 +01:00
|
|
|
|
|
|
|
|
namespace lumiera {
|
2011-05-28 01:46:06 +02:00
|
|
|
namespace facade {
|
|
|
|
|
|
2018-04-03 03:14:55 +02:00
|
|
|
/**
|
|
|
|
|
* Implementation Base
|
|
|
|
|
* for building Facade Proxy implementations.
|
|
|
|
|
* Typically the purpose of such a proxy is to route
|
|
|
|
|
* any calls through the C-Bindings of the Lumiera Interface system.
|
|
|
|
|
* The actual instance and thus the storage for the concrete proxy object
|
|
|
|
|
* is controlled via lib::DependInject::ServiceInstance, which in turn is
|
|
|
|
|
* embedded into and thus linked to the lifetime of a InstanceHandle to
|
|
|
|
|
* connect via Lumiera's Interface/Plug-in system. Typically the actual
|
|
|
|
|
* Service implementation object will hold an instance of that InstanceHandle
|
|
|
|
|
* and thus tie the opening/closing of the interface and access mechanism
|
|
|
|
|
* to the service lifecycle.
|
|
|
|
|
*/
|
2011-05-28 01:46:06 +02:00
|
|
|
template<class IHA>
|
2018-04-03 04:58:22 +02:00
|
|
|
struct Binding;
|
2018-04-03 03:14:55 +02:00
|
|
|
|
|
|
|
|
template<class FA, class I>
|
2018-04-03 04:58:22 +02:00
|
|
|
struct Binding<InstanceHandle<I,FA>>
|
2018-04-03 03:14:55 +02:00
|
|
|
: public FA
|
|
|
|
|
{
|
|
|
|
|
typedef InstanceHandle<I,FA> IHandle;
|
|
|
|
|
typedef Binding<IHandle> IBinding;
|
|
|
|
|
|
|
|
|
|
I& _i_;
|
|
|
|
|
|
|
|
|
|
Binding (IHandle const& iha)
|
|
|
|
|
: _i_(iha.get())
|
|
|
|
|
{ }
|
|
|
|
|
};
|
2009-01-06 06:15:36 +01:00
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
|
2018-04-03 04:58:22 +02:00
|
|
|
|
|
|
|
|
template<class I, class FA>
|
|
|
|
|
Link<I,FA>::Link (IH const& iha)
|
|
|
|
|
: ServiceHandle<I,FA>{iha}
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
template<class I, class FA>
|
|
|
|
|
Link<I,FA>::~Link() { }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class I, class FA>
|
|
|
|
|
FA*
|
|
|
|
|
Link<I,FA>::operator->() const
|
|
|
|
|
{
|
|
|
|
|
return ServiceHandle<I,FA>::operator->();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-05-28 01:46:06 +02:00
|
|
|
}} // namespace lumiera::facade
|
2009-01-06 06:09:46 +01:00
|
|
|
|
2009-01-04 15:21:04 +01:00
|
|
|
#endif
|