diff --git a/doc/devel/uml/class141957.html b/doc/devel/uml/class141957.html new file mode 100644 index 000000000..9158a22a5 --- /dev/null +++ b/doc/devel/uml/class141957.html @@ -0,0 +1,20 @@ + + + + + + +Class ProcDispatcher + + + + + +
Class ProcDispatcher
+

+ + + + +

Declaration :

Component(s) : Dispatcher

+ diff --git a/src/common/appconfig.cpp b/src/common/appconfig.cpp index 17a245cdf..b708d42d0 100644 --- a/src/common/appconfig.cpp +++ b/src/common/appconfig.cpp @@ -33,29 +33,37 @@ using util::isnil; +using util::cStr; namespace lumiera { #ifndef LUMIERA_VERSION -#define LUMIERA_VERSION 3++devel +#define LUMIERA_VERSION 0++devel #endif - /** perform initialization on first access. - * A call is placed in static initialization code - * included in lumiera.h; thus it will happen - * probably very early. + /** perform initialization triggered on first access. + * Will execute the ON_BASIC_INIT hook, but under typical + * circumstances this is a NOP, because when callbacks are + * added to this hook, the Appconfig singleton instance has + * already been created. For this reason, there is special + * treatment for the ON_BASIC_INIT in LifecycleHook::add, + * causing the provided callbacks being fired immediately. + * (btw, this is nothing to be worried of, for the client + * code it just behaves like intended). */ Appconfig::Appconfig() - : configParam_ (new Configmap) + : configParam_ (new Configmap), + lifecycleHooks_(new LifecycleRegistry) { ////////// NOBUG_INIT; ////////// INFO(config, "Basic application configuration triggered."); + lifecycleHooks_->execute (ON_BASIC_INIT); // note in most cases a NOP // install our own handler for undeclared exceptions std::set_unexpected (lumiera::error::lumiera_unexpectedException); @@ -67,11 +75,8 @@ namespace lumiera - /** access the configuation value for a given key. - * @return empty string for unknown keys, else the corresponding configuration value - */ const string & - Appconfig::get (const string & key) throw() + Appconfig::get (const string & key) { try { @@ -82,10 +87,64 @@ namespace lumiera catch (...) { ERROR(config, "error while accessing configuration parameter \"%s\".", key.c_str()); - throw lumiera::error::Fatal (); + static string NOTFOUND (""); + return NOTFOUND; } } + void + Appconfig::lifecycle (Symbol event_label) + { + instance().lifecycleHooks_->execute(event_label); + } + + + // ==== implementation LifecycleHook class ======= + + typedef LifecycleRegistry::Hook Callback; + + + LifecycleHook::LifecycleHook (Symbol eventLabel, Callback callbackFun) + { + this->add (eventLabel,callbackFun); + } + + LifecycleHook& + LifecycleHook::add (Symbol eventLabel, Callback callbackFun) + { + Appconfig::instance().lifecycleHooks_->enroll (eventLabel,callbackFun); + + if (!strcmp(ON_BASIC_INIT, eventLabel)) + callbackFun(); // when this code executes, + // then per definition we are already post "basic init" + // (which happens in the Appconfig ctor); thus fire it immediately + return *this; + } + + + } // namespace lumiera + +// ==== implementation C interface ======= + +void +lumiera_LifecycleHook_add (const char* eventLabel, void callbackFun(void)) +{ + lumiera::LifecycleHook (eventLabel, callbackFun); +} + + +void +lumiera_Lifecycle_execute (const char* eventLabel) +{ + lumiera::Appconfig::lifecycle (eventLabel); +} + + +const char* +lumiera_Appconfig_get (const char* key) +{ + return cStr (lumiera::Appconfig::get(key)); +} diff --git a/src/common/appconfig.hpp b/src/common/appconfig.hpp index 984236755..92180fe60 100644 --- a/src/common/appconfig.hpp +++ b/src/common/appconfig.hpp @@ -22,15 +22,18 @@ */ /** @file appconfig.hpp - ** This header is special, as it causes global system initialisation - ** to happen. On inclusion, it places static initialisation code, - ** which on first run will create the Appconfig singleton instance. - ** Additionally, the inclusion, configuration and initialisation - ** of the NoBug library is handled here. Global definitions - ** for NoBug are placed into the corresponding translation unit - ** appconfig.cpp" + ** Registering and managing some application-global services. + ** Besides \link Appconfig::get querying \endlink for some + ** "Application property" constants, there is a mechanism for + ** registering and firing off application lifecycle event hooks. + ** The implementation of some subsystem can define a static instance + ** variable of class LifecycleHook, which will place the provided + ** callback function into a central registry accessable through + ** the Appconfig singleton instance. ** - ** @see nobugcfg.h + ** @see lumiera.cpp + ** @see nobugcfg.cpp + ** @see sessmanagerimpl.cpp */ @@ -40,6 +43,8 @@ #include #include #include +#include +#include "common/lifecycleregistry.hpp" #include "nobugcfg.h" @@ -49,6 +54,7 @@ namespace lumiera { using std::string; using boost::scoped_ptr; + using boost::noncopyable; /** @@ -59,14 +65,14 @@ namespace lumiera * @warning don't use Appconfig in destuctors. */ class Appconfig + : private noncopyable { private: /** perform initialization on first access. - * @see #instance() for Lifecycle */ + * @see #instance() */ Appconfig (); - Appconfig (const Appconfig&); ///< copy prohibited, not implemented - ~Appconfig () throw() {}; ///< deletion prohibited + ~Appconfig () throw() {}; ///< deletion prohibited friend void boost::checked_delete(Appconfig*); @@ -85,24 +91,70 @@ namespace lumiera /** access the configuation value for a given key. * @return empty string for unknown keys, config value else - * @todo do we need such a facility? */ - static const string & get (const string& key) throw(); + static const string & get (const string& key); // never throws + /** fire off all lifecycle callbacks + * registered under the given label */ + static void lifecycle (Symbol eventLabel); + + // note: if necessary, we can add support + // for querying the current lifecycle phase... private: typedef std::map Configmap; - typedef std::auto_ptr PConfig; + typedef scoped_ptr PConfig; + typedef scoped_ptr PLife; - /** @todo the following is just placeholder code! - * Appconfig could do such things if necessary, - * or provide similar "allways available" services. - */ PConfig configParam_; + PLife lifecycleHooks_; + friend class LifecycleHook; + + }; + + + Symbol ON_BASIC_INIT ("ON_BASIC_INIT"); ///< automatic static init. treated specially + Symbol ON_GLOBAL_INIT ("ON_GLOBAL_INIT"); ///< to be triggered in main() @note no magic! + Symbol ON_GLOBAL_SHUTDOWN ("ON_GLOBAL_SHUTDOWN"); ///< to be triggered at the end of main() @note no magic! + + // client code is free to register and use additional lifecycle events + + + /** + * define and register a callback for some lifecycle event. + * The purpose of this class is to be defined as a static variable + * in the implementation of some subsystem (i.e. in the cpp file), + * providing the ctor with the pointer to a callback function. + * Thus the callback gets enrolled when the corresponding object + * file is loaded. The event ON_BASIC_INIT is handled specifically, + * firing off the referred callback function as soon as possible. + * All other lables are just arbitrary (string) constants and it + * is necessary that "someone" cares to fire off the lifcycle events + * at the right place. For example, lumiera-main (and the test runner) + * calls \c Appconfig::instance().execute(ON_GLOBAL_INIT) (and..SHUTDOWN) + */ + class LifecycleHook + : private noncopyable + { + public: + LifecycleHook (Symbol eventLabel, LifecycleRegistry::Hook callbackFun); + + LifecycleHook& add (Symbol eventLabel, LifecycleRegistry::Hook callbackFun); ///< for chained calls (add multiple callbacks) }; } // namespace lumiera + + +extern "C" { //TODO provide a separate header if some C code happens to need this... + + void lumiera_LifecycleHook_add (const char* eventLabel, void callbackFun(void)); + void lumiera_Lifecycle_execute (const char* eventLabel); + const char* lumiera_Appconfig_get (const char* key); + +} + + #endif diff --git a/src/common/lifecycleregistry.hpp b/src/common/lifecycleregistry.hpp new file mode 100644 index 000000000..8b17a33b6 --- /dev/null +++ b/src/common/lifecycleregistry.hpp @@ -0,0 +1,101 @@ +/* + LIFECYCLEREGISTRY.hpp - registry for application lifecycle callbacks + + Copyright (C) Lumiera.org + 2008, Christian Thaeter + 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 lifecycleregistry.hpp + ** Helper for registering lifecycle event callbacks, which are + ** provided as a global service by lumiera::Appconfig. This service + ** allows to enroll functions under a given label and then to call + ** all those registered functions. + ** @note this is in fact an event mechanism, and if we start using + ** more than just this basic functionallity, we should switch to + ** boost::signals. (which has the downside of being an binary + ** dependency). + ** + ** @see appconfig.hpp + */ + + +#ifndef LUMIERA_LIFECYCLE_H +#define LUMIERA_LIFECYCLE_H + +#include +#include +//#include +//#include +#include +#include + + + +namespace lumiera + { +// using std::string; +// using boost::scoped_ptr; + using boost::noncopyable; + using boost::function; + + typedef const char * const Symbol; + + + /** + * Registry of callback functions accessable by a label (ID) + * provided at registration. Registered functions will be added + * to a list, which can be triggered via label. Used by Appconfig + * to implement the lumiera lifecycle (init, shutdown) hooks. + */ + class LifecycleRegistry + : private noncopyable + { + public: + typedef boost::function Hook; + typedef std::vector Callbacks; + typedef Callbacks::iterator Iter; + + + void enroll (Symbol label, Hook& toCall) + { + table_[label].push_back(toCall); + } + + void execute (Symbol label) + { + Callbacks& cbs (table_[label]); + Iter e = cbs.end(); + for (Iter p = cbs.begin(); + p != e; ++p) + (*p)(); // invoke callback + } + + + private: + std::map table_; + + LifecycleRegistry () {} + friend class Appconfig; + + }; + + + +} // namespace lumiera +#endif diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index ec1c64ef9..2ed5141c8 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -61,7 +61,7 @@ #include #include -#include +#include #include #include diff --git a/src/proc/mobject/session.hpp b/src/proc/mobject/session.hpp index 7b9dfd4ef..d91e5f32a 100644 --- a/src/proc/mobject/session.hpp +++ b/src/proc/mobject/session.hpp @@ -37,7 +37,7 @@ #include "proc/mobject/session/defsmanager.hpp" #include "common/singleton.hpp" -#include +#include #include diff --git a/tests/50components.tests b/tests/50components.tests index 63e97cf9a..2bac409cb 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -107,6 +107,11 @@ out: dtor ~TargetObj(12) successfull END +TEST "LifeCycle_test" LifeCycle_test < [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ] out: removed 0 ---> [ 1, 2, 3, 4, 5, 6, 7, 8, 9, ] diff --git a/tests/common/appconfigtest.cpp b/tests/common/appconfigtest.cpp index 6cab57de8..215c8c46c 100644 --- a/tests/common/appconfigtest.cpp +++ b/tests/common/appconfigtest.cpp @@ -1,5 +1,5 @@ /* - Appconfig(Test) - accessing the allwasy-available Appconfig singleton + Appconfig(Test) - accessing the allways-available Appconfig singleton Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -28,9 +28,6 @@ #include "common/util.hpp" -#include -using std::cout; - namespace lumiera diff --git a/tests/common/lifecycletest.cpp b/tests/common/lifecycletest.cpp new file mode 100644 index 000000000..5e5a779a1 --- /dev/null +++ b/tests/common/lifecycletest.cpp @@ -0,0 +1,78 @@ +/* + LifeCycle(Test) - checking the lifecycle callback hooks provided by Appconfig + + 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 "common/appconfig.hpp" + +#include "common/test/run.hpp" +#include "common/util.hpp" + + + + +namespace lumiera + { + namespace test + { + + bool basicInit (false); + bool customCallback (false); + + void basicInitHook () { basicInit = true; } + void myCallback() { customCallback = true; } + + Symbol MY_MAGIC_MEGA_EVENT = "dial M for murder"; + + + namespace // register them to be invoced by lifecycle event id + { + LifecycleHook _schedule1 (ON_BASIC_INIT, &basicInitHook); + LifecycleHook _schedule2 (MY_MAGIC_MEGA_EVENT, &myCallback); + } + + + /** @test the global lifecycle hooks got registered, + * the ON_BASIC_INIT hook has been already called, + * while our custom callback can be trigged at our will + */ + class LifeCycle_test : public Test + { + virtual void + run (Arg arg) + { + ASSERT (basicInit, "the basic-init callback hasn't been invoked automatically"); + + ASSERT (!customCallback); + Appconfig::lifecycle (MY_MAGIC_MEGA_EVENT); + ASSERT ( customCallback); + } + + }; + + LAUNCHER (LifeCycle_test, "function common"); + + + } // namespace test + +} // namespace util +