* Lumiera source code always was copyrighted by individual contributors * there is no entity "Lumiera.org" which holds any copyrights * Lumiera source code is provided under the GPL Version 2+ == Explanations == Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above. For this to become legally effective, the ''File COPYING in the root directory is sufficient.'' The licensing header in each file is not strictly necessary, yet considered good practice; attaching a licence notice increases the likeliness that this information is retained in case someone extracts individual code files. However, it is not by the presence of some text, that legally binding licensing terms become effective; rather the fact matters that a given piece of code was provably copyrighted and published under a license. Even reformatting the code, renaming some variables or deleting parts of the code will not alter this legal situation, but rather creates a derivative work, which is likewise covered by the GPL! The most relevant information in the file header is the notice regarding the time of the first individual copyright claim. By virtue of this initial copyright, the first author is entitled to choose the terms of licensing. All further modifications are permitted and covered by the License. The specific wording or format of the copyright header is not legally relevant, as long as the intention to publish under the GPL remains clear. The extended wording was based on a recommendation by the FSF. It can be shortened, because the full terms of the license are provided alongside the distribution, in the file COPYING.
341 lines
8.2 KiB
C++
341 lines
8.2 KiB
C++
/*
|
||
SessionServiceAccess(Test) - accessing implementation level session services
|
||
|
||
Copyright (C)
|
||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**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-service-access-test.cpp
|
||
** unit test \ref SessionServiceAccess_test
|
||
*/
|
||
|
||
|
||
#include "lib/test/run.hpp"
|
||
#include "steam/mobject/session.hpp"
|
||
#include "lib/meta/generator.hpp"
|
||
#include "lib/format-cout.hpp"
|
||
#include "lib/depend.hpp"
|
||
|
||
#include <boost/lexical_cast.hpp>
|
||
#include <memory>
|
||
#include <string>
|
||
|
||
|
||
namespace steam {
|
||
namespace mobject {
|
||
namespace session {
|
||
namespace test {
|
||
|
||
using lib::Depend;
|
||
using boost::lexical_cast;
|
||
using std::unique_ptr;
|
||
using std::string;
|
||
|
||
|
||
namespace { // what follows is a simulated (simplified) version
|
||
// of the complete Session + SessionManager setup.....
|
||
|
||
using lib::meta::Types;
|
||
using lib::meta::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<class API, class IMPL>
|
||
struct TServiceAccessPoint;
|
||
|
||
template<class IMPL>
|
||
struct TServiceAccessPoint<InternalAPI_1, IMPL>
|
||
: IMPL
|
||
, InternalAPI_1
|
||
{
|
||
uint
|
||
getMagic ()
|
||
{
|
||
return IMPL::magic_;
|
||
}
|
||
};
|
||
|
||
template<class IMPL>
|
||
struct TServiceAccessPoint<InternalAPI_2, IMPL>
|
||
: IMPL
|
||
{
|
||
void
|
||
forwardServiceInvocation()
|
||
{
|
||
IMPL::implementationService();
|
||
}
|
||
};
|
||
|
||
template< typename IMPS
|
||
, class FRONT
|
||
, class SESS
|
||
>
|
||
class TSessionServices
|
||
: public InstantiateChained<typename IMPS::List, TServiceAccessPoint, SESS>
|
||
{
|
||
public:
|
||
|
||
static FRONT& current;
|
||
|
||
template<class API>
|
||
API&
|
||
get()
|
||
{
|
||
return *this;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
/* === storage and basic session manager configuration === */
|
||
|
||
struct TSessManagerImpl;
|
||
|
||
typedef TSessionServices< Types<InternalAPI_1,InternalAPI_2>
|
||
, TSessManagerImpl
|
||
, TSessionImpl
|
||
> SessionImplAPI;
|
||
|
||
|
||
|
||
struct TSessManagerImpl : TSessManager
|
||
{
|
||
unique_ptr<SessionImplAPI> pImpl_;
|
||
|
||
TSessManagerImpl()
|
||
: pImpl_{}
|
||
{ }
|
||
|
||
SessionImplAPI*
|
||
operator-> ()
|
||
{
|
||
if (!pImpl_)
|
||
this->reset();
|
||
return pImpl_.get();
|
||
}
|
||
|
||
|
||
/* ==== Manager API ==== */
|
||
void
|
||
reset ()
|
||
{
|
||
unique_ptr<SessionImplAPI> tmpS {new SessionImplAPI};
|
||
pImpl_.swap (tmpS);
|
||
}
|
||
};
|
||
|
||
|
||
uint TSessionImpl::magic_;
|
||
|
||
TSessManager& TSession::current = Depend<TSessManagerImpl>()();
|
||
//note: already during static initialisation
|
||
|
||
template<>
|
||
TSessManagerImpl& SessionImplAPI::current = static_cast<TSessManagerImpl&> (TSession::current);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/* === Implementation of service access === */ //----------------corresponding-to-session-services.cpp
|
||
|
||
InternalAPI_1&
|
||
InternalAPI_1::access()
|
||
{
|
||
return SessionImplAPI::current->get<InternalAPI_1>();
|
||
}
|
||
|
||
void
|
||
InternalAPI_2::invokeImplementationService()
|
||
{
|
||
SessionImplAPI::current->forwardServiceInvocation();
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/* === Implementation of Session internals === */ //----------------corresponding-to-session-impl.cpp
|
||
|
||
TSessionImpl::operator string() const
|
||
{
|
||
return string("Session-Impl(")
|
||
+ lexical_cast<string>(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 Steam-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 Steam-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 steam::mobject::session::test
|