/* SessManagerImpl - global session access and lifecycle Copyright (C) Lumiera.org 2008, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. 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. * *****************************************************/ /** @file sess-manager-impl.cpp ** Implementation of the Session management functions. ** The Class SessManager is declared alongside with mobject::Session, ** because it serves as smart ptr-to-Impl at the same time. Effectively, ** the session manager owns the current session object and only grants ** access via his overloaded operator->() . Because there is no operator*(), ** no one can get at the address of the current session object. (correct?) ** ** TODO: this is an implementation draft, awaiting integration with several other facilities //////////////////TICKET #704 ** ** @see session-impl.hpp ** @see mobject::Session#current ** @see mobject::session::SessionManager_test ** */ #include "lib/error.hpp" #include "proc/mobject/session.hpp" #include "proc/mobject/session/sess-manager-impl.hpp" #include "proc/mobject/session/lifecycle-advisor.hpp" #include "proc/config-resolver.hpp" #include "proc/asset/timeline.hpp" #include "common/query/defs-manager.hpp" #include "common/query.hpp" using boost::scoped_ptr; namespace proc { namespace mobject { namespace session { LUMIERA_ERROR_DEFINE (CREATE_SESSION, "unable to create basic session"); /** Access to the "current session", which actually is * an SessionImpl instance. This session object is created * either by loading an existing session, or on demand by * this accessor function here (when no session was loaded * or created) * @note any exceptions arising while building the basic * session object(s) will halt the system. */ SessionImplAPI* SessManagerImpl::operator-> () throw() { if (!pSess_) try { // create empty default configured session this->reset(); } catch (...) { ERROR (progress, "Unrecoverable Failure while creating the empty default session."); throw lumiera::error::Fatal ( "Failure while creating the basic session object. System halted." , LUMIERA_ERROR_CREATE_SESSION ); } return pSess_.get(); } namespace { // defining details of the Session Lifecycle typedef scoped_ptr SessionPImpl; class SessionLifecycleDetails : public LifecycleAdvisor { SessionPImpl & session_; bool shall_load_; ////////////TODO a placeholder; later we'll pass in a de-serialiser /** @note Any session services get up into default configured state. * After the swap, \c tmpS holds onto the old session, which * consequently should unwind on leaving this scope. */ void createSessionFacilities() { INFO (session, "Initialising new Session...."); SessionPImpl tmpS (new SessionImplAPI); session_.swap (tmpS); } void injectSessionContent() { if (shall_load_) { UNIMPLEMENTED ("loading session from persistent storage"); } else { // inject some default session content REQUIRE (0 == session_->timelines.size(), "injecting default timeline, but session isn't pristine"); // issue a default query to retrieve or create a Timeline and a default Sequence asset::PTimeline initialTimeline = session_->defaults (lumiera::Query ("")); // these got registered automatically ENSURE (1 == session_->timelines.size()); ENSURE (initialTimeline == session_->timelines[0]); } } void getSessionReady() { INFO (session, "Session ready for use."); } void openSessionInterface() { TODO ("open public session interface"); /////////////////////// TICKET #699 } void closeSessionInterface() { /////////////////////// TICKET #699 INFO (session, "closing session interfaces."); TODO ("actually close session interfaces :) and don't babble in the log when NOT closing anything..."); } void disconnectRenderProcesses() { TODO ("halt rendering"); //////////////////////////////////////// TICKET #703 TODO ("possibly terminate builder"); ////////////////////////////// TICKET #201 } void commandLogCheckpoint() { //////////////////////////////////////// TICKET #697 INFO (command, " Session shutdown. Command processing stopped."); } void deconfigure() { session_->defaults.clear(); ConfigResolver::instance().reset(); // forget any configuration rules AssetManager::instance().clear(); /////////////////////////////////////////////////////////////////// TICKET #154 } public: SessionLifecycleDetails(SessionPImpl& currentSessionAccessPoint) : session_(currentSessionAccessPoint) , shall_load_(false) { } }; }//(End) details of Session Lifecycle /** Starting up the session access and lifecycle management. * Initially (at static init time), only the single system-wide * Session manger instance is created. It can be used to load an * existing session; otherwise an empty default Session, together * with the core facilities (PlacementIndex, AssetManager, Query * subsystem and the Defaults manager) is created on first * \link #operator-> access \endlink to the session object. */ SessManagerImpl::SessManagerImpl () throw() : pSess_ (0) , lifecycle_(new SessionLifecycleDetails(pSess_)) { Session::initFlag = true; //////////////////////////////////////// TICKET #518 instead of this hack, implement basic-init of the session manager for real } SessManagerImpl::~SessManagerImpl () { //////////////////////////////////////// TICKET #845 verify sane session manager lifecycle here Session::initFlag = false; } bool SessManagerImpl::isUp () { return bool(pSess_); ///////////////////// TICKET #702 possible race, because this gets true way before the interface is up } /** @note no transactional behaviour. may succeed partially. * @todo clarify relation to command processing/undo /////////// TICKET #697 */ void SessManagerImpl::clear () { Lock sync(this); pSess_->clear(); } /** Shut down the current session together with all associated services. * @todo avoid blocking when aborting render processes ///////////// TICKET #201 * @todo well defined transactional behaviour ///////////////////// TICKET #698 */ void SessManagerImpl::close () { Lock sync(this); if (isUp()) lifecycle_->shutDown(); pSess_.reset(); } /** @todo error handling, how to deal with a partially configured session? * @todo for \c reset() to work, we need to change the implementation of * AssetManager so support this kind of transactional switch! */ void SessManagerImpl::reset () { Lock sync(this); if (isUp()) lifecycle_->shutDown(); lifecycle_->pullUp(); } void SessManagerImpl::load () { UNIMPLEMENTED ("load serialised session"); Lock sync(this); if (isUp()) lifecycle_->shutDown(); lifecycle_->pullUp(); } /** \par Implementation details * We intend to have several switchable object serialisers. * One of these serialisers should generate a comprehensible * text based representation suitable for checking into * SCM systems. * Sessions can be saved into one single file or be split * to several files (master file and edl files) */ void SessManagerImpl::save () { UNIMPLEMENTED ("save session (serialised)"); /////////////////////////////////////////////////TODO: need lock? } }}} // namespace proc::mobject::session