/* SessionServiceAccess(Test) - accessing implementation level session services 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. * *****************************************************/ #include "lib/test/run.hpp" #include "proc/mobject/session.hpp" #include "lib/meta/generator.hpp" #include "lib/singleton.hpp" #include #include #include namespace mobject { namespace session { namespace test { using lib::Singleton; using boost::lexical_cast; using std::ostream; using std::string; using std::cout; using std::endl; namespace { // what follows is a simulated (simplified) version // of the complete Session + SessionManager setup..... using lumiera::typelist::Types; using lumiera::typelist::InstantiateChained; /* === Interface level === */ //----------------corresponding-to-session.hpp struct TSessManager; typedef TSessManager& PSess; struct TSession { virtual ~TSession () { } static TSessManager& current; virtual void externalOperation () =0; }; struct TSessManager { /** access to the current session */ virtual TSession* operator-> () =0; virtual void reset () =0; virtual ~TSessManager() { }; }; /* === Service level API === */ //----------------internal-API-definition-headers struct InternalAPI_1 { virtual ~InternalAPI_1() {} virtual uint getMagic() =0; static InternalAPI_1& access(); }; struct InternalAPI_2 { static void invokeImplementationService(); }; /* === Implementation level === */ //----------------corresponding-to-session-impl.hpp struct TSessionImpl : TSession { static uint magic_; /* ==== Session API ==== */ void externalOperation() ; /* ==== Implementation level API ==== */ void implementationService() ; /* ==== internals ==== */ TSessionImpl(); operator string() const; }; template struct TServiceAccessPoint; template struct TServiceAccessPoint : IMPL , InternalAPI_1 { uint getMagic () { return IMPL::magic_; } }; template struct TServiceAccessPoint : IMPL { void forwardServiceInvocation() { IMPL::implementationService(); } }; template< typename IMPS , class FRONT , class SESS > class TSessionServices : public InstantiateChained { public: static FRONT& current; template API& get() { return *this; } }; /* === storage and basic session manager configuration === */ struct TSessManagerImpl; typedef TSessionServices< Types , TSessManagerImpl , TSessionImpl > SessionImplAPI; struct TSessManagerImpl : TSessManager { scoped_ptr pImpl_; TSessManagerImpl() : pImpl_(0) { } SessionImplAPI* operator-> () { if (!pImpl_) this->reset(); return pImpl_.get(); } /* ==== Manager API ==== */ void reset () { scoped_ptr tmpS (new SessionImplAPI); pImpl_.swap (tmpS); } }; uint TSessionImpl::magic_; TSessManager& TSession::current = Singleton()(); //note: already during static initialisation template<> TSessManagerImpl& SessionImplAPI::current = static_cast (TSession::current); /* === Implementation of service access === */ //----------------corresponding-to-session-services.cpp InternalAPI_1& InternalAPI_1::access() { return SessionImplAPI::current->get(); } void InternalAPI_2::invokeImplementationService() { SessionImplAPI::current->forwardServiceInvocation(); } /* === Implementation of Session internals === */ //----------------corresponding-to-session-impl.cpp inline ostream& operator<< (ostream& os, TSessionImpl const& simpl) { return os << string(simpl); } TSessionImpl::operator string() const { return string("Session-Impl(") + lexical_cast(magic_) + ")"; } TSessionImpl::TSessionImpl() { ++magic_; cout << "creating new Session " << magic_ << endl; } void TSessionImpl::externalOperation() { cout << *this << "::externalOperation()" << endl; } /* ==== Implementation level API ==== */ inline void TSessionImpl::implementationService() { cout << *this << "::implementationService()" << endl; } } // (END) simulated session management /******************************************************************************* * Verify the access mechanism both to the pubic session API and * to implementation level APIs used by Proc-Layer internals. * * Actually, this test uses a simulated setup of the real session, * complete with interfaces, implementation and session manager frontend. * * @see session-impl.hpp the real thing * @see SessionServices; */ class SessionServiceAccess_test : public Test { virtual void run (Arg) { access_defaultSession(); make_newSession(); invoke_implServices(); } /** @test accessing an non-existing session * causes creation of a new TSessionImpl instance. * After that, the public API function gets invoked. */ void access_defaultSession () { cout << "Session not yet used...." << endl; TSession::current->externalOperation(); } /** @test invoking the management API to close the session. * The next public API invocation will create * a new TSessionImpl instance. */ void make_newSession () { TSession::current.reset(); TSession::current->externalOperation(); } /** example of an one-liner, as it might be used * internally by implementation code within Proc-Layer */ uint magic() { return InternalAPI_1::access().getMagic(); } /** @test accessing implementation-level APIs */ void invoke_implServices () { cout << "current Session-Impl-ID = " << magic() << endl; InternalAPI_2::invokeImplementationService(); cout << "now resetting this session." << endl; TSession::current.reset(); InternalAPI_2::invokeImplementationService(); // invocation creates new session as side effect cout << "current Session-Impl-ID = " << magic() << endl; } }; /** Register this test class... */ LAUNCHER (SessionServiceAccess_test, "function session"); }}} // namespace mobject::session::test