/** * @file lleventdispatcher.h * @author Nat Goodspeed * @date 2009-06-18 * @brief Central mechanism for dispatching events by string name. This is * useful when you have a single LLEventPump listener on which you can * request different operations, vs. instantiating a different * LLEventPump for each such operation. * * $LicenseInfo:firstyear=2009&license=viewergpl$ * Copyright (c) 2009, Linden Research, Inc. * $/LicenseInfo$ */ #if ! defined(LL_LLEVENTDISPATCHER_H) #define LL_LLEVENTDISPATCHER_H #include #include #include #include #include #include "llevents.h" class LLSD; /** * Given an LLSD map, examine a string-valued key and call a corresponding * callable. This class is designed to be contained by an LLEventPump * listener class that will register some of its own methods, though any * callable can be used. */ class LL_COMMON_API LLEventDispatcher { public: LLEventDispatcher(const std::string& desc, const std::string& key); virtual ~LLEventDispatcher(); /// Accept any C++ callable, typically a boost::bind() expression typedef boost::function Callable; /** * Register a @a callable by @a name. The optional @a required parameter * is used to validate the structure of each incoming event (see * llsd_matches()). */ void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD()); /** * Special case: a subclass of this class can pass an unbound member * function pointer without explicitly specifying the * boost::bind() expression. */ template void add(const std::string& name, void (CLASS::*method)(const LLSD&), const LLSD& required=LLSD()) { addMethod(name, method, required); } /// Overload for both const and non-const methods template void add(const std::string& name, void (CLASS::*method)(const LLSD&) const, const LLSD& required=LLSD()) { addMethod(name, method, required); } /// Unregister a callable bool remove(const std::string& name); /// Call a registered callable with an explicitly-specified name. If no /// such callable exists, die with LL_ERRS. If the @a event fails to match /// the @a required prototype specified at add() time, die with LL_ERRS. void operator()(const std::string& name, const LLSD& event) const; /// Extract the @a key value from the incoming @a event, and call the /// callable whose name is specified by that map @a key. If no such /// callable exists, die with LL_ERRS. If the @a event fails to match the /// @a required prototype specified at add() time, die with LL_ERRS. void operator()(const LLSD& event) const; private: template void addMethod(const std::string& name, const METHOD& method, const LLSD& required) { CLASS* downcast = dynamic_cast(this); if (! downcast) { addFail(name, typeid(CLASS).name()); } else { add(name, boost::bind(method, downcast, _1), required); } } void addFail(const std::string& name, const std::string& classname) const; /// try to dispatch, return @c true if success bool attemptCall(const std::string& name, const LLSD& event) const; std::string mDesc, mKey; typedef std::map > DispatchMap; DispatchMap mDispatch; }; /** * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class * that contains (or derives from) LLDispatchListener need only specify the * LLEventPump name and dispatch key, and add() its methods. Incoming events * will automatically be dispatched. */ class LL_COMMON_API LLDispatchListener: public LLEventDispatcher { public: LLDispatchListener(const std::string& pumpname, const std::string& key); std::string getPumpName() const { return mPump.getName(); } private: bool process(const LLSD& event); LLEventStream mPump; LLTempBoundListener mBoundListener; }; #endif /* ! defined(LL_LLEVENTDISPATCHER_H) */