/** * @RDE_HEADER@ * AvmExerciseContext * $Id$ * $HeadURL$ * $Author$ * Created by Christian Fröbel, NLSE, 2018-07-30 */ #pragma once #include #include #include namespace LtsSession { class LtsSessionDataDds; } namespace OperatorManagement { namespace Interface { class Dtc; } } namespace ExerciseManagement { namespace Interface { class Dtc; } } namespace InfrastructureManagement { namespace Interface { class Dtc; } } namespace AudioVideoManagement { namespace Interface { class Dtc; class Ftc; } class StreamNameMapping; /** * For each Exercise -- as defined by its Id -- AvmExerciseContextManager manages * an associated ExerciseContext. The ExerciseContext just holds all necessary entities. * The idea is that any number of PluginInterface-instances with the same exerciseId * share the same ExerciseContext. * For example, all PluginInterface-instances for Exercise 42 can share the *same* Dtc or Ftc. * Thus Dtc and Ftc are part of the ExerciseContext. * * The lifetime of an ExerciseContext can be longer than the lifetime of a PluginInterface-instance. * AvsSessionContext uses (references) entities from the ExerciseContext. * This is ok as it is guaranteed that the lifetime of the ExerciseContext is at least as long * as the lifetime of AvsSessionContext. * Actually they have the same lifetime -- if an AvsSessionContext exists. * * The difference is that there can be at most one AvsSessionContext at the same time. * But there can be at most one ExerciseContext *for each* exerciseId at the same time. * For the global exercise (exerciseId 0) there is never an AvsSessionContext. * * The following picuture illustrates the lifetimes: * * App1 (42) --------- --------- * App2 (42) --------- --------- * App3 (35) ========= * * ExerciseContext (42) --------- --------------- --------- * ExerciseContext (35) ========= * * AvsSessionContext (42) --------- --------------- * AvsSessionContext (35) ========= * * PluginInterface-instance 1 (42) --------- * PluginInterface-instance 2 (42) --------- * PluginInterface-instance 3 (42) --------- * PluginInterface-instance 4 (35) ========= * PluginInterface-instance 5 (42) --------- * * @see AvsSessionContext * @author Christian Fröbel */ class AvmExerciseContextManager { public: struct ExerciseContext; ~AvmExerciseContextManager(); /** * Don't use directly; use AvmExerciseContextHandle instead. */ ///@{ ExerciseContext *acquire(int exerciseId, LtsSession::LtsSessionDataDds *session); void release(int exerciseId, ExerciseContext *composite); ///@} private: /** * Small internal helper class in order to keep track of the refCount. * Here, the refCount denotes the number of PluginInterface-Instances for the same Exercise. */ struct RefCountedContext { explicit RefCountedContext(std::unique_ptr &&context); RefCountedContext(RefCountedContext &&) noexcept; ~RefCountedContext(); int refCount{1}; std::unique_ptr context; }; using ExerciseId = int; std::map m_activeContexts; }; /** * Helper class to automatically call AvmExerciseContextManager::acquire() * and AvmExerciseContextManager::release() in the ctor and dtor respectively. * Instances can be moved but not copied. * * @author Christian Fröbel */ class AvmExerciseContextHandle { public: AvmExerciseContextHandle(); AvmExerciseContextHandle(AvmExerciseContextManager *context, int exerciseId, LtsSession::LtsSessionDataDds *session); operator bool() const { return m_context.get(); } /** Only available when not in global Exercise */ StreamNameMapping *streamNameMapping() const; const std::shared_ptr &dtc() const; const std::shared_ptr &ftc() const; OperatorManagement::Interface::Dtc *opmDtc() const; ExerciseManagement::Interface::Dtc *exmDtc() const; InfrastructureManagement::Interface::Dtc *ismDtc() const; private: using Releaser = std::function; std::unique_ptr m_context; }; } // namespace AudioVideoManagement