Lumiera
0.pre.03
»edit your freedom«
|
Go to the source code of this file.
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 instancehandle.hppinterface instance handle"" 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.
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"
void*
unfortunately.The Interface/Plug-in system offers two basic usage scenarios
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()
to yield a reference to a proxy object implementing XYZInterface
.
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 window of availability, any access through the proxy factory throws an lumiera::error::Fatal. Any sort of dependency management is outside the scope of the InstanceHandle (for the core 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 descriptors.)
For the Layer separation interfaces, the process of loading and opening is abstracted as 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.
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.
Definition in file interfaceproxy.hpp.
Classes | |
struct | Binding< IHA > |
Implementation Base for building Facade Proxy implementations. More... | |
struct | Binding< InstanceHandle< I, FA > > |
Namespaces | |
lumiera | |
Lumiera public interface. | |