/* SessionServices - accessing Steam-Layer internal session implementation services Copyright (C) 2008, Hermann Vosseler   **Lumiera** 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. See the file COPYING for further details. * *****************************************************************/ /** @file session-services.cpp ** Implementation of some top-level internal services of the session. ** The Session is _the_ central interface to access the model and thus the ** edit being worked on. Behind the scenes, it needs to operate several technically ** quite involved services, which we prefer to hide away as implementation details. ** Typically, each of these services defines a dedicated interface, and is implemented ** by delegating to a set of more specialised facilities. ** ** The following services are integrated here ** - service to access a Placement by (hash) ID ** - service to attach or remove session content, while maintaining all indices ** - service to query and explore session contents ** - service to inject mock content for unit testing ** - service to manage and discover default settings by resolution query ** ** @todo WIP implementation of session core from 2010 ** @todo as of 2016, this effort is considered stalled but basically valid */ #include "steam/mobject/session/session-service-fetch.hpp" #include "steam/mobject/session/session-service-mutate.hpp" #include "steam/mobject/session/session-service-explore-scope.hpp" #include "steam/mobject/session/session-service-mock-index.hpp" #include "steam/mobject/session/session-service-defaults.hpp" #include "steam/mobject/session/session-services.hpp" #include "steam/mobject/session/session-impl.hpp" #include "steam/mobject/session/sess-manager-impl.hpp" #include "steam/mobject/session/mobjectfactory.hpp" #include "lib/symbol.hpp" using lib::Symbol; namespace steam { namespace mobject { namespace session { /** is the element-fetch service usable? * Effectively this means: is the session up? */ bool SessionServiceFetch::isAccessible () { return Session::initFlag and Session::current.isUp(); } /** 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) { return SessionImplAPI::current->isRegisteredID (placementID); } /** 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 SteamDispatcher * 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) { return SessionImplAPI::current->resolveID (placementID); } /** attach an object by placement onto the session. * Implemented by registering a copy of the Placement into the * PlacementIndex in the session. This copy establishes a new kind of * "object instance", represented by a new placement-ID, which is returned * and can be used to refer to this "instance" within the session from now on. * @param scope the (existing) parent scope where to attach the new element */ PlacementMO::ID const& SessionServiceMutate::attach_toModel(PMO newPlacement, PID scope) { return SessionImplAPI::current->insertCopy (newPlacement,scope); } /** detach the denoted element from the model _including all children_. * @return true if actually erased something * @note when specifying model root, all sub-elements will be cleared, * but model root itself will be retained. */ bool SessionServiceMutate::detach_and_clear (PID scope) { return SessionImplAPI::current->purgeScopeRecursively (scope); } /** detach the denoted leaf element from the model. * @return true if actually erased something * @throw error::Fatal when attempting to remove the model root * @throw error::State when the given element contains sub elements */ bool SessionServiceMutate::detach (PID leafElement) { return SessionImplAPI::current->detachElement (leafElement); } namespace { // deleter function to clean up test/mock PlacementIndex void remove_testIndex (PlacementIndex* testIdx) { REQUIRE (testIdx); SessionImplAPI::current->reset_PlacementIndex(); // restore default Index from Session testIdx->clear(); ASSERT (0 == testIdx->size()); delete testIdx; } } /** Re-define the implicit PlacementIndex temporarily, e.g. for unit tests. */ PPIdx SessionServiceMockIndex:: install () { Symbol typeID ("dummyRoot"); PMO dummyRoot (MObject::create (typeID)); PPIdx mockIndex (new PlacementIndex(dummyRoot), &remove_testIndex); // manage instance lifecycle ENSURE (mockIndex); ENSURE (mockIndex->isValid()); ENSURE (1 == mockIndex.use_count()); SessionImplAPI::current->reset_PlacementIndex (mockIndex.get()); return mockIndex; } /** @return resolver for DiscoveryQuery instances, actually backed by PlacementIndex */ QueryResolver const& SessionServiceExploreScope::getResolver() { return SessionImplAPI::current->getScopeQueryResolver(); } /** @return root scope of the current model (session datastructure) */ PlacementMO& SessionServiceExploreScope::getScope (PlacementMO const& placementToLocate) { return SessionImplAPI::current->getScope(placementToLocate); } PlacementMO& SessionServiceExploreScope::getScope (PlacementMO::ID const& placementToLocate) { return SessionImplAPI::current->getScope(placementToLocate); } /** @return root scope of the current model (session datastructure) */ PlacementMO& SessionServiceExploreScope::getScopeRoot() { return SessionImplAPI::current->getScopeRoot(); } }}} // namespace steam::mobject::session