implement two of the SessionServices (internal APIs)

providing implementation-level access to the PlacementIndex
and especially installing a mock index for unit tests
This commit is contained in:
Fischlurch 2009-11-11 05:30:24 +01:00
parent 7da8844581
commit 1a76ce7a5f
6 changed files with 88 additions and 23 deletions

View file

@ -49,6 +49,7 @@
#include "lib/error.hpp"
#include "proc/mobject/placement.hpp"
#include "proc/mobject/explicitplacement.hpp" /////////////TODO this is ugly! Why can't placement::resolve() return a reference??
#include "proc/mobject/session/session-service-fetch.hpp"
//#include <tr1/memory>
@ -60,13 +61,6 @@ namespace mobject {
class MObject;
namespace session {
// see placement-index.cpp
Placement<MObject> & fetch_PlacementIndex(Placement<MObject>::ID const&) ;
bool checkContains_PlacementIndex (Placement<MObject>::ID const& pID) ;
}
LUMIERA_ERROR_DECLARE (INVALID_PLACEMENTREF); ///< unresolvable placement reference, or of incompatible type
@ -210,7 +204,7 @@ namespace mobject {
bool
checkValidity () const
{
return session::checkContains_PlacementIndex(this->id_);
return session::SessionServiceFetch::isRegisteredID (this->id_);
}
static void
@ -240,7 +234,7 @@ namespace mobject {
static PlacementMO&
access (_Id const& placementID)
{
Placement<MObject> & pla (session::fetch_PlacementIndex (placementID)); // may throw
Placement<MObject> & pla (session::SessionServiceFetch::resolveID (placementID)); // may throw
REQUIRE (pla.isValid());
ASSERT (pla.isCompatible<MO>());
return static_cast<PlacementMO&> (pla);

View file

@ -27,9 +27,17 @@
** to control the behaviour of the editing part of the application.
** All all implementation complexities are hidden behind a "PImpl".
**
** This file contains the implementation classes, it should never
** be included by client code.
** This file contains the implementation level API, it should never
** be included by client code. Besides the actual SessionImpl, a set
** of further implementation level services is provided for use by
** Proc-Layer's internals. These additional SessionServices are to be
** accessed through dedicated headers and interface classes (typically
** through static access functions), thereby abstracting from the actual
** session implementation. Within this file, the implementation of these
** SessionServices is wired up with the SessionImpl object.
**
** @see Session public API
** @see session-services.hpp
** @see session-service-access-test.cpp for a complete simplified mock session manager
**
*/
@ -94,6 +102,13 @@ namespace session {
void clear ();
PPIdx const&
getPlacementIndex()
{
ENSURE (pIdx_);
return pIdx_;
}
};
@ -106,14 +121,13 @@ namespace session {
bool
isRegisteredID (PMO::ID const& placementID)
{
UNIMPLEMENTED ("check if index contains the given ID");
return IMPL::getPlacementIndex()->contains (placementID); //never throws
}
PMO&
resolveID (PMO::ID const& placementID)
{
UNIMPLEMENTED ("fetch from PlacementIndex, throw on failure");
// IMPL::implementationService();
return IMPL::getPlacementIndex()->find (placementID); //may throw
}
};
@ -136,7 +150,23 @@ namespace session {
struct ServiceAccessPoint<SessionServiceMockIndex, IMPL>
: IMPL
{
////////////////////////////TODO
PPIdx const&
getPlacementIndex()
{
if (mockIndex_)
return mockIndex_;
else
return IMPL::getPlacementIndex();
}
void
reset_PlacementIndex (PPIdx const& alternativeIndex)
{
mockIndex_ = alternativeIndex;
}
private:
PPIdx mockIndex_;
};

View file

@ -51,9 +51,16 @@ namespace session {
// using lumiera::typelist::InheritFrom;
// using lumiera::typelist::NullType;
/**
* Implementation-level service for resolving an Placement-ID.
* Usually, this service is backed by the PlacementIndex of the
* current session -- however, for the purpose of unit testing,
* this index may be overlaid temporarily, by using the
* SessionServiceMockIndex API.
*/
class SessionServiceFetch
{
public:
static PlacementMO& resolveID (PlacementMO::ID const&) ;
static bool isRegisteredID (PlacementMO::ID const&) ;
};

View file

@ -38,6 +38,7 @@
#ifndef MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H
#define MOBJECT_SESSION_SESSION_SERVICE_MOCK_INDEX_H
#include "proc/mobject/session/placement-index.hpp"
//#include "proc/mobject/session.hpp"
//#include "lib/meta/generator.hpp"
@ -51,9 +52,18 @@ namespace session {
// using lumiera::typelist::InheritFrom;
// using lumiera::typelist::NullType;
/** there is an implicit PlacementIndex available on a global level,
* by default implemented within the current session. This Service
* to re-define this implicit index temporarily, e.g. for unit tests.
* @param alternativeIndex alternative Index instance to install.
* when \c NIL, then restore access to the PlacementIndex
* instance always available within the SessionImpl
*/
class SessionServiceMockIndex
{
public:
void reset_PlacementIndex (PPIdx const& alternativeIndex =PPIdx());
};

View file

@ -32,7 +32,10 @@
namespace mobject {
namespace session {
/** TODO */
/** verify the given placement-ID (hash) is valid,
* by checking if it refers to a Placement instance
* currently registered with the PlacementIndex of the
* active Session. */
bool
SessionServiceFetch::isRegisteredID (PlacementMO::ID const& placementID)
{
@ -40,6 +43,16 @@ namespace session {
}
/** actually retrieve a Placement tracked by the index.
* @param placementID hash-ID, typically from a PlacementRef
* @throw error::Invalid if the ID isn't resolvable
* @note the returned ref is guaranteed to be valid and usable
* only \em now, which means, by virtue of the ProcDispatcher
* and command processing, during this operation. It can be
* used to invoke an operation, but should never be stored;
* rather, client code should create an MObjectRef, if
* bound to store an reference for later.
*/
PlacementMO&
SessionServiceFetch::resolveID (PlacementMO::ID const& placementID)
{
@ -47,5 +60,15 @@ namespace session {
}
/** */
void
SessionServiceMockIndex::reset_PlacementIndex (PPIdx const& alternativeIndex)
{
return SessionImplAPI::current->reset_PlacementIndex (alternativeIndex);
}
}} // namespace mobject::session

View file

@ -3522,7 +3522,7 @@ Then, running the goal {{{:-resolve(T, stream(T,mpeg)).}}} would search a Track
In the design of the Lumiera Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Pipe, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered &quot;condiguration data&quot; (including the actual plugin implementation to be loaded)
</pre>
</div>
<div title="QueryResolver" modifier="Ichthyostega" modified="200910301615" created="200910210300" tags="Rules spec draft img" changecount="25">
<div title="QueryResolver" modifier="Ichthyostega" modified="200911090412" created="200910210300" tags="Rules spec draft img" changecount="26">
<pre>Within the Lumiera Proc-Layer, there is a general preference for issuing [[queries|Query]] over hard wired configuration (or even mere table based configuration). This leads to the demand of exposing a //possibility to issue queries// &amp;mdash; without actually disclosing much details of the facility implementing this service. For example, for shaping the general session interface (in 10/09), we need a means of exposing a hook to discover HighLevelModel contents, without disclosing how the model is actually organised internally (namely by using an PlacementIndex).
!Analysis of the problem
@ -3541,7 +3541,7 @@ The situation can be decomposed as follows.[&gt;img[QueryResolver|uml/fig137733.
* and then there is the notorious problem of re-gaining the specifically typed context //behind//&amp;nbsp; the invocation interface. Especially, the facility processing the query needs to know both the expected result type and details about the concrete query and its parametrisation. &lt;br/&gt;&amp;rarr; TypedQueryProblem
!!!Entities and Operations
The //client// &amp;nbsp;(code using query-resolver.hpp) either wants a ''goal'' or ''query'' to be resolved; the former is just implicitly typed and usually given in predicate logic from, while the latter may be a specialised subclass templated to yield objects of a specific type as results. A ''query resolver'' is an (abstracted) entity capable of //resolving//&amp;nbsp; such a goal. Actually, behind the scenes there is somehow a registration of the concrete resolving facilities, which are asumed to decide about their ability of handling a given goal. Issuing a goal or query yields a ''resolution'' &amp;mdash; practically speaking, a set of indivitual solutions. These individual solution ''results'' can be explored by ''iteration'', thereby moving an embedded ''cursor'' through the ''result set''. Any result can be retrieved at most once &amp;mdash; after that, the resolution is ''exhausted'' and will be released automatically when the expolration iterator goes out of scope.
The //client// &amp;nbsp;(code using query-resolver.hpp) either wants a ''goal'' or ''query'' to be resolved; the former is just implicitly typed and usually given in predicate logic from ({{red{planned as of 11/09}}}), while the latter may be a specialised subclass templated to yield objects of a specific type as results. A ''query resolver'' is an (abstracted) entity capable of //resolving//&amp;nbsp; such a goal. Actually, behind the scenes there is somehow a registration of the concrete resolving facilities, which are asumed to decide about their ability of handling a given goal. Issuing a goal or query yields a ''resolution'' &amp;mdash; practically speaking, a set of indivitual solutions. These individual solution ''results'' can be explored by ''iteration'', thereby moving an embedded ''cursor'' through the ''result set''. Any result can be retrieved at most once &amp;mdash; after that, the resolution is ''exhausted'' and will be released automatically when the expolration iterator goes out of scope.
!!!Decisions
* while, in the use case currently at hand, the query instance is created by the client on the stack, the possibility of managing the queries internally is deliberately kept open. Because otherwise, we had to commit to a specific way of obtaining results, for example by assuming always to use an embedded STL iterator.
@ -3950,7 +3950,7 @@ Currently as of 5/09, this is an ongoing [[implementation and planning effort|Pl
{{red{WIP ... just emerging}}}</pre>
</div>
<div title="SessionLifecycle" modifier="Ichthyostega" modified="200911090241" created="200911070329" tags="SessionLogic spec" changecount="20">
<div title="SessionLifecycle" modifier="Ichthyostega" modified="200911090647" created="200911070329" tags="SessionLogic spec" changecount="21">
<pre>The current [[Session]] is the root of any state found within Proc-Layer. Thus, events defining the session's lifecycle influence and synchronise the cooperative behaviour of the entities within the model, the ProcDispatcher, [[Fixture]] and any facility below.
* when ''starting'', on first access an empty session is created, which puts any related facility into a defined initial state.
* when ''closing'' the session, any dependent facilities are disabled, disconnected, halted or closed
@ -3991,6 +3991,7 @@ As detailed above, {{{Session::current}}} exposes the management / lifecycle API
# the PlacementIndex is cleared, effectively releasing any object &quot;instances&quot;
# the [[asset registry|AssetManager]] is cleared, thereby releasing any remaining external resource references
# destruction of session implementation instances
{{red{none of the above is implemented as of 11/09}}}
</pre>
</div>
<div title="SessionLogic" modifier="Ichthyostega" modified="200911071754" created="200904242110" tags="overview" changecount="15">
@ -4004,8 +4005,8 @@ Currently (as of 5/09), Ichthyo is [[targeting|PlanningSessionInMem]] a first pr
Objects are attached and manipulated by [[placements|Placement]]; thus the organisation of these placements is part of the session data layout. Effectively, such a placement within the session behaves like an //instances// of a given object, and at the same time it defines the &quot;non-substantial&quot; properties of the object, e.g. its positions and relations. [[References|MObjectRef]] to these placement entries are handed out as parameters, both down to the [[Builder]] and from there to the render processes within the engine, but also to external parts within the GUI and in plugins. The actual implementation of these object references is built on top of the PlacementRef tags, thus relying on the PlacementIndex the session maintains to keep track of all placements and their relations. While &amp;mdash; using these references &amp;mdash; an external client can access the objects and structures within the session, any actual ''mutations'' should be done based on the CommandHandling: a single operation of a sequence of operations is defined as [[Command]], to be [[dispatched as mutation operation|ProcDispatcher]]. Following this policy ensures integration with the&amp;nbsp;SessionStorage and provides (unlimited) [[UNDO|UndoManager]].
</pre>
</div>
<div title="SessionManager" modifier="Ichthyostega" created="200911071838" tags="SessionLogic def" changecount="1">
<pre>The session manager is responsible for maintaining session state as a whole and for conducting the session lifecycle. The session manager API allows for saving, loading, closing and resetting the session. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Actually, both session and session manager are interfaces.
<div title="SessionManager" modifier="Ichthyostega" modified="200911090408" created="200911071838" tags="SessionLogic def" changecount="2">
<pre>The session manager is responsible for maintaining session state as a whole and for conducting the session [[lifecycle|SessionLifecycle]]. The session manager API allows for saving, loading, closing and resetting the session. Accessible through the static interface {{{Session::current}}}, it exposes the actual session as a ~PImpl. Actually, both session and session manager are interfaces.
</pre>
</div>
<div title="SessionOverview" modifier="Ichthyostega" modified="200911071816" created="200709272105" tags="design img" changecount="38">