From db7172df29e40623a1972ea72fb05e3ffb3a9c20 Mon Sep 17 00:00:00 2001
From: Ichthyostega
Date: Tue, 3 Apr 2018 06:28:29 +0200
Subject: [PATCH] DOC: update technical (doxygen) documentation to reflect the
integration with lib::Depend
---
src/common/instancehandle.hpp | 78 ++++++++++------
src/include/gui-notification-facade.h | 2 +-
src/include/interfaceproxy.hpp | 125 ++++++++++++++++----------
src/include/session-command-facade.h | 2 +-
wiki/thinkPad.ichthyo.mm | 97 ++++++++++++--------
5 files changed, 195 insertions(+), 109 deletions(-)
diff --git a/src/common/instancehandle.hpp b/src/common/instancehandle.hpp
index fdfd9470d..c61be7d3a 100644
--- a/src/common/instancehandle.hpp
+++ b/src/common/instancehandle.hpp
@@ -1,5 +1,5 @@
/*
- INSTANCEHANDLE.hpp - automatically handling interface lifecycle
+ INSTANCEHANDLE.hpp - automatically handling interface lifecycle
Copyright (C) Lumiera.org
2008, Hermann Vosseler
@@ -32,7 +32,7 @@
** @see gui::GuiFacade usage example
** @see interface.h
** @see interfaceproxy.hpp (more explanations)
- ** @see interfaceproxy.cpp (Implementation of the proxies)
+ ** @see session-command-interface-proxy.cpp (Proxy implementation example)
**
*/
@@ -66,17 +66,17 @@ namespace lumiera {
namespace { // implementation details
void
- throwIfError()
+ throwIfError()
{
if (lumiera_error_peek())
throw lumiera::error::Config("failed to open interface or plugin.",lumiera_error());
}
-
+
/** takes a (single) instance definitions, as typically created
* when defining interfaces for external use, and registers it
* with the InterfaceSystem. Then uses the data found in the
* \em given instance descriptor to open an instance handle.
- * @throws error::Config when the registration process fails
+ * @throws error::Config when the registration process fails
*/
LumieraInterface
register_and_open (LumieraInterface descriptor)
@@ -97,22 +97,33 @@ namespace lumiera {
verify_validity (LumieraInterface ifa)
{
REQUIRE (ifa);
- return (ifa == lumiera_interfaceregistry_interface_find (ifa->interface,
- ifa->version,
+ return (ifa == lumiera_interfaceregistry_interface_find (ifa->interface,
+ ifa->version,
ifa->name));
}
-
- } // (End) impl details
+ } // (End) impl details
+
+
+
namespace facade {
-
+
+ /**
+ * to be specialised and implemented for each
+ * individual interface and facade interface.
+ * The actual proxy implements the facade interface
+ * and reroutes each call to the corresponding function
+ * on the CL-Interface for the Lumiera interface system.
+ */
template
class Proxy;
+ /** The ServiceHandle automatically creates and manages the Proxy instance */
template
using ServiceHandle = typename lib::DependInject::template ServiceInstance>>;
+
/**
* @internal Helper/Adapter for establishing a link
* between an InstanceHandle and a facade interface,
@@ -179,7 +190,7 @@ namespace lumiera {
>
class InstanceHandle
: util::NonCopyable
- {
+ {
LumieraInterface desc_;
I* instance_;
facade::Link facadeLink_;
@@ -194,14 +205,14 @@ namespace lumiera {
*/
InstanceHandle (string const& iName, uint version, size_t minminor, string const& impName)
: desc_(0)
- , instance_(reinterpret_cast
+ , instance_(reinterpret_cast
(lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str())))
, facadeLink_(*this)
- {
+ {
throwIfError();
}
- /** Set up an InstanceHandle managing the
+ /** Set up an InstanceHandle managing the
* registration and deregistration of interface(s).
* Should be placed at the service providing side.
* @param a (single) interface descriptor, which can be created with
@@ -211,7 +222,7 @@ namespace lumiera {
: desc_(descriptor)
, instance_(reinterpret_cast (register_and_open (desc_)))
, facadeLink_(*this)
- {
+ {
throwIfError();
}
@@ -224,24 +235,41 @@ namespace lumiera {
- /** act as smart pointer providing access through the facade.
- * @note we don't provide operator* */
- FA * operator-> () const { return facadeLink_.operator ->(); }
+ /** act as smart pointer to allow access through the facade.
+ * @note we don't provide `operator*`
+ */
+ FA*
+ operator-> () const
+ {
+ return facadeLink_.operator ->();
+ }
/** directly access the instance via the CL interface */
- I& get () const { ENSURE(instance_); return *instance_; }
+ I&
+ get () const
+ {
+ ENSURE(instance_);
+ return *instance_;
+ }
-
- explicit operator bool() const { return isValid(); }
- bool operator! () const { return not isValid();}
+ explicit
+ operator bool() const
+ {
+ return isValid();
+ }
+ bool
+ operator!() const
+ {
+ return not isValid();
+ }
private:
- bool
+ bool
isValid() const
- {
- return instance_
+ {
+ return instance_
&& verify_validity (&instance_->interface_header_);
}
};
diff --git a/src/include/gui-notification-facade.h b/src/include/gui-notification-facade.h
index 2ebee467d..4e06607e7 100644
--- a/src/include/gui-notification-facade.h
+++ b/src/include/gui-notification-facade.h
@@ -137,6 +137,6 @@ LUMIERA_INTERFACE_DECLARE (lumieraorg_GuiNotification, 0,
#ifdef __cplusplus
-}
+}// extern "C"
#endif
#endif /*GUI_GUI_NOTIFICATION_H*/
diff --git a/src/include/interfaceproxy.hpp b/src/include/interfaceproxy.hpp
index c9404922c..261d3a95d 100644
--- a/src/include/interfaceproxy.hpp
+++ b/src/include/interfaceproxy.hpp
@@ -21,71 +21,102 @@
*/
/** @file interfaceproxy.hpp
- ** Facade Interfaces Lifecycle. Communication between the Layers within Lumiera
- ** usually is routed through *Layer Separation Interfaces*. These are comprised
- ** of a Facade interface and a equivalent rendering as C Language interface defined
- ** with the help of the Interface/Plugin system. But in order to be able to actually
- ** access a service via this Facade, you need an instance of the interface.
+ ** 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.
**
- ** lumiera::facade::Proxy and InstanceHandle together are used to create such an concrete
- ** instance of the Facade interface. It is implemented such as to route each call
- ** through the corresponding C Language function defined in the Interface/Plugin system.
- ** Typically there is another subclass of the Facade interfaces sitting "on the other side"
- ** of the interface barrier and actually implementing the functionality. The template
- ** facade::Accessor can be thought of as a factory creating such a proxy instance of the
- ** facade interface for the client code to use. Typically, an instance of the _factory_
- ** is embedded (as a static functor member object) right within the otherwise abstract
- ** facade interface, this way allowing the client code to write e.g. `XYZInterface::facade()`
+ ** 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`
+ ** 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`, so client code can write e.g. `XYZInterface::facade()`
** to yield a reference to a proxy object implementing `XYZInterface`.
**
+ **
** # Interface Lifecycle
**
** 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::State.
+ ** 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. When creating such an InstanceHandle using the appropriate
- ** template and ctor parameters, in addition to the registration with the Interface/Plugin
- ** system, the corresponding facade::Proxy factory is addressed and the interface instance
- ** is "opened" by creating the appropriate proxy object instance. Similarly, when the
- ** InstanceHandle object goes out of scope, prior to detaching from the Interface/Proxy
- ** system, the corresponding lumiera::facade::Accessor frontend is "closed", which
- ** additionally means destroying the proxy object instance and switching any
- ** further access to throwing and exception.
+ ** 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 interfaceproxy.hpp
- ** in turn), there needs to be an actual implementation of each proxy object located in
- ** some translation unit. The usual place is interfaceproxy.cpp, which gets linked into
- ** `liblumieracommon.so` and contains actual specialisations and literal forwarding
- ** code _for each individual facade._
- ** @todo
- ** 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),
- ** in order to get RAII-style registration of interfaces and loading of plug-ins.
+ ** # Usage
**
- ** 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 relevant specialisations _need to be included explicitly_ into this
- ** compilation unit!
+ ** 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.
**
- ** 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.
- **
- ** @see interface.h
- ** @see plugin.h
- ** @see lumiera::Subsys
- ** @see guinotification.h usage example (facade interface)
- ** @see guinotification-facade.cpp corresponding implementation within the GUI
+ ** @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
*/
diff --git a/src/include/session-command-facade.h b/src/include/session-command-facade.h
index fee2c54c1..5c1205e8d 100644
--- a/src/include/session-command-facade.h
+++ b/src/include/session-command-facade.h
@@ -133,6 +133,6 @@ LUMIERA_INTERFACE_DECLARE (lumieraorg_SessionCommand, 0,
#ifdef __cplusplus
-}
+}// extern "C"
#endif
#endif /*PROC_CONTROL_SESSION_COMMAND_H*/
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 133234dc1..e5f50c990 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -28028,7 +28028,7 @@
-
+
@@ -28059,7 +28059,7 @@
-
+
@@ -28089,8 +28089,8 @@
-
-
+
+
@@ -28144,7 +28144,7 @@
-
+
@@ -28155,7 +28155,7 @@
-
+
@@ -28199,7 +28199,7 @@
-
+
@@ -28251,7 +28251,7 @@
-
+
@@ -28290,8 +28290,8 @@
-
-
+
+
@@ -28340,7 +28340,7 @@
-
+
@@ -28475,8 +28475,8 @@
-
-
+
+
@@ -28485,7 +28485,7 @@
-
+
@@ -28513,7 +28513,7 @@
-
+
@@ -28527,23 +28527,43 @@
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
-
+
+
+
+
+
+
+
+ ...wir müssen immer, für jeden Proxy
+
+
+ explizit eine Template-Instaniierung triggern, und zwar für
+
+
+
+
+
+
+
+
@@ -28562,13 +28582,15 @@
-
+
+
-
+
+
@@ -28587,13 +28609,17 @@