PageRenderTime 65ms CodeModel.GetById 20ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/lleventdispatcher.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 672 lines | 423 code | 56 blank | 193 comment | 57 complexity | fd77be389a54e4d834a3278638616a20 MD5 | raw file
  1/**
  2 * @file   lleventdispatcher.cpp
  3 * @author Nat Goodspeed
  4 * @date   2009-06-18
  5 * @brief  Implementation for lleventdispatcher.
  6 * 
  7 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#if LL_WINDOWS
 30#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
 31#endif
 32
 33// Precompiled header
 34#include "linden_common.h"
 35// associated header
 36#include "lleventdispatcher.h"
 37// STL headers
 38// std headers
 39// external library headers
 40// other Linden headers
 41#include "llevents.h"
 42#include "llerror.h"
 43#include "llsdutil.h"
 44#include "stringize.h"
 45#include <memory>                   // std::auto_ptr
 46
 47/*****************************************************************************
 48*   LLSDArgsSource
 49*****************************************************************************/
 50/**
 51 * Store an LLSD array, producing its elements one at a time. Die with LL_ERRS
 52 * if the consumer requests more elements than the array contains.
 53 */
 54class LL_COMMON_API LLSDArgsSource
 55{
 56public:
 57    LLSDArgsSource(const std::string function, const LLSD& args);
 58    ~LLSDArgsSource();
 59
 60    LLSD next();
 61
 62    void done() const;
 63
 64private:
 65    std::string _function;
 66    LLSD _args;
 67    LLSD::Integer _index;
 68};
 69
 70LLSDArgsSource::LLSDArgsSource(const std::string function, const LLSD& args):
 71    _function(function),
 72    _args(args),
 73    _index(0)
 74{
 75    if (! (_args.isUndefined() || _args.isArray()))
 76    {
 77        LL_ERRS("LLSDArgsSource") << _function << " needs an args array instead of "
 78                                  << _args << LL_ENDL;
 79    }
 80}
 81
 82LLSDArgsSource::~LLSDArgsSource()
 83{
 84    done();
 85}
 86
 87LLSD LLSDArgsSource::next()
 88{
 89    if (_index >= _args.size())
 90    {
 91        LL_ERRS("LLSDArgsSource") << _function << " requires more arguments than the "
 92                                  << _args.size() << " provided: " << _args << LL_ENDL;
 93    }
 94    return _args[_index++];
 95}
 96
 97void LLSDArgsSource::done() const
 98{
 99    if (_index < _args.size())
100    {
101        LL_WARNS("LLSDArgsSource") << _function << " only consumed " << _index
102                                   << " of the " << _args.size() << " arguments provided: "
103                                   << _args << LL_ENDL;
104    }
105}
106
107/*****************************************************************************
108*   LLSDArgsMapper
109*****************************************************************************/
110/**
111 * From a formal parameters description and a map of arguments, construct an
112 * arguments array.
113 *
114 * That is, given:
115 * - an LLSD array of length n containing parameter-name strings,
116 *   corresponding to the arguments of a function of interest
117 * - an LLSD collection specifying default parameter values, either:
118 *   - an LLSD array of length m <= n, matching the rightmost m params, or
119 *   - an LLSD map explicitly stating default name=value pairs
120 * - an LLSD map of parameter names and actual values for a particular
121 *   function call
122 * construct an LLSD array of actual argument values for this function call.
123 *
124 * The parameter-names array and the defaults collection describe the function
125 * being called. The map might vary with every call, providing argument values
126 * for the described parameters.
127 *
128 * The array of parameter names must match the number of parameters expected
129 * by the function of interest.
130 *
131 * If you pass a map of default parameter values, it provides default values
132 * as you might expect. It is an error to specify a default value for a name
133 * not listed in the parameters array.
134 *
135 * If you pass an array of default parameter values, it is mapped to the
136 * rightmost m of the n parameter names. It is an error if the default-values
137 * array is longer than the parameter-names array. Consider the following
138 * parameter names: ["a", "b", "c", "d"].
139 *
140 * - An empty array of default values (or an isUndefined() value) asserts that
141 *   every one of the above parameter names is required.
142 * - An array of four default values [1, 2, 3, 4] asserts that every one of
143 *   the above parameters is optional. If the current parameter map is empty,
144 *   they will be passed to the function as [1, 2, 3, 4].
145 * - An array of two default values [11, 12] asserts that parameters "a" and
146 *   "b" are required, while "c" and "d" are optional, having default values
147 *   "c"=11 and "d"=12.
148 *
149 * The arguments array is constructed as follows:
150 *
151 * - Arguments-map keys not found in the parameter-names array are ignored.
152 * - Entries from the map provide values for an improper subset of the
153 *   parameters named in the parameter-names array. This results in a
154 *   tentative values array with "holes." (size of map) + (number of holes) =
155 *   (size of names array)
156 * - Holes are filled with the default values.
157 * - Any remaining holes constitute an error.
158 */
159class LL_COMMON_API LLSDArgsMapper
160{
161public:
162    /// Accept description of function: function name, param names, param
163    /// default values
164    LLSDArgsMapper(const std::string& function, const LLSD& names, const LLSD& defaults);
165
166    /// Given arguments map, return LLSD::Array of parameter values, or LL_ERRS.
167    LLSD map(const LLSD& argsmap) const;
168
169private:
170    static std::string formatlist(const LLSD&);
171
172    // The function-name string is purely descriptive. We want error messages
173    // to be able to indicate which function's LLSDArgsMapper has the problem.
174    std::string _function;
175    // Store the names array pretty much as given.
176    LLSD _names;
177    // Though we're handed an array of name strings, it's more useful to us to
178    // store it as a map from name string to position index. Of course that's
179    // easy to generate from the incoming names array, but why do it more than
180    // once?
181    typedef std::map<LLSD::String, LLSD::Integer> IndexMap;
182    IndexMap _indexes;
183    // Generated array of default values, aligned with the array of param names.
184    LLSD _defaults;
185    // Indicate whether we have a default value for each param.
186    typedef std::vector<char> FilledVector;
187    FilledVector _has_dft;
188};
189
190LLSDArgsMapper::LLSDArgsMapper(const std::string& function,
191                               const LLSD& names, const LLSD& defaults):
192    _function(function),
193    _names(names),
194    _has_dft(names.size())
195{
196    if (! (_names.isUndefined() || _names.isArray()))
197    {
198        LL_ERRS("LLSDArgsMapper") << function << " names must be an array, not " << names << LL_ENDL;
199    }
200    LLSD::Integer nparams(_names.size());
201    // From _names generate _indexes.
202    for (LLSD::Integer ni = 0, nend = _names.size(); ni < nend; ++ni)
203    {
204        _indexes[_names[ni]] = ni;
205    }
206
207    // Presize _defaults() array so we don't have to resize it more than once.
208    // All entries are initialized to LLSD(); but since _has_dft is still all
209    // 0, they're all "holes" for now.
210    if (nparams)
211    {
212        _defaults[nparams - 1] = LLSD();
213    }
214
215    if (defaults.isUndefined() || defaults.isArray())
216    {
217        LLSD::Integer ndefaults = defaults.size();
218        // defaults is a (possibly empty) array. Right-align it with names.
219        if (ndefaults > nparams)
220        {
221            LL_ERRS("LLSDArgsMapper") << function << " names array " << names
222                                      << " shorter than defaults array " << defaults << LL_ENDL;
223        }
224
225        // Offset by which we slide defaults array right to right-align with
226        // _names array
227        LLSD::Integer offset = nparams - ndefaults;
228        // Fill rightmost _defaults entries from defaults, and mark them as
229        // filled
230        for (LLSD::Integer i = 0, iend = ndefaults; i < iend; ++i)
231        {
232            _defaults[i + offset] = defaults[i];
233            _has_dft[i + offset] = 1;
234        }
235    }
236    else if (defaults.isMap())
237    {
238        // defaults is a map. Use it to populate the _defaults array.
239        LLSD bogus;
240        for (LLSD::map_const_iterator mi(defaults.beginMap()), mend(defaults.endMap());
241             mi != mend; ++mi)
242        {
243            IndexMap::const_iterator ixit(_indexes.find(mi->first));
244            if (ixit == _indexes.end())
245            {
246                bogus.append(mi->first);
247                continue;
248            }
249
250            LLSD::Integer pos = ixit->second;
251            // Store default value at that position in the _defaults array.
252            _defaults[pos] = mi->second;
253            // Don't forget to record the fact that we've filled this
254            // position.
255            _has_dft[pos] = 1;
256        }
257        if (bogus.size())
258        {
259            LL_ERRS("LLSDArgsMapper") << function << " defaults specified for nonexistent params "
260                                      << formatlist(bogus) << LL_ENDL;
261        }
262    }
263    else
264    {
265        LL_ERRS("LLSDArgsMapper") << function << " defaults must be a map or an array, not "
266                                  << defaults << LL_ENDL;
267    }
268}
269
270LLSD LLSDArgsMapper::map(const LLSD& argsmap) const
271{
272    if (! (argsmap.isUndefined() || argsmap.isMap() || argsmap.isArray()))
273    {
274        LL_ERRS("LLSDArgsMapper") << _function << " map() needs a map or array, not "
275                                  << argsmap << LL_ENDL;
276    }
277    // Initialize the args array. Indexing a non-const LLSD array grows it
278    // to appropriate size, but we don't want to resize this one on each
279    // new operation. Just make it as big as we need before we start
280    // stuffing values into it.
281    LLSD args(LLSD::emptyArray());
282    if (_defaults.size() == 0)
283    {
284        // If this function requires no arguments, fast exit. (Don't try to
285        // assign to args[-1].)
286        return args;
287    }
288    args[_defaults.size() - 1] = LLSD();
289
290    // Get a vector of chars to indicate holes. It's tempting to just scan
291    // for LLSD::isUndefined() values after filling the args array from
292    // the map, but it's plausible for caller to explicitly pass
293    // isUndefined() as the value of some parameter name. That's legal
294    // since isUndefined() has well-defined conversions (default value)
295    // for LLSD data types. So use a whole separate array for detecting
296    // holes. (Avoid std::vector<bool> which is known to be odd -- can we
297    // iterate?)
298    FilledVector filled(args.size());
299
300    if (argsmap.isArray())
301    {
302        // Fill args from array. If there are too many args in passed array,
303        // ignore the rest.
304        LLSD::Integer size(argsmap.size());
305        if (size > args.size())
306        {
307            // We don't just use std::min() because we want to sneak in this
308            // warning if caller passes too many args.
309            LL_WARNS("LLSDArgsMapper") << _function << " needs " << args.size()
310                                       << " params, ignoring last " << (size - args.size())
311                                       << " of passed " << size << ": " << argsmap << LL_ENDL;
312            size = args.size();
313        }
314        for (LLSD::Integer i(0); i < size; ++i)
315        {
316            // Copy the actual argument from argsmap
317            args[i] = argsmap[i];
318            // Note that it's been filled
319            filled[i] = 1;
320        }
321    }
322    else
323    {
324        // argsmap is in fact a map. Walk the map.
325        for (LLSD::map_const_iterator mi(argsmap.beginMap()), mend(argsmap.endMap());
326             mi != mend; ++mi)
327        {
328            // mi->first is a parameter-name string, with mi->second its
329            // value. Look up the name's position index in _indexes.
330            IndexMap::const_iterator ixit(_indexes.find(mi->first));
331            if (ixit == _indexes.end())
332            {
333                // Allow for a map containing more params than were passed in
334                // our names array. Caller typically receives a map containing
335                // the function name, cruft such as reqid, etc. Ignore keys
336                // not defined in _indexes.
337                LL_DEBUGS("LLSDArgsMapper") << _function << " ignoring "
338                                            << mi->first << "=" << mi->second << LL_ENDL;
339                continue;
340            }
341            LLSD::Integer pos = ixit->second;
342            // Store the value at that position in the args array.
343            args[pos] = mi->second;
344            // Don't forget to record the fact that we've filled this
345            // position.
346            filled[pos] = 1;
347        }
348    }
349
350    // Fill any remaining holes from _defaults.
351    LLSD unfilled(LLSD::emptyArray());
352    for (LLSD::Integer i = 0, iend = args.size(); i < iend; ++i)
353    {
354        if (! filled[i])
355        {
356            // If there's no default value for this parameter, that's an
357            // error.
358            if (! _has_dft[i])
359            {
360                unfilled.append(_names[i]);
361            }
362            else
363            {
364                args[i] = _defaults[i];
365            }
366        }
367    }
368    // If any required args -- args without defaults -- were left unfilled
369    // by argsmap, that's a problem.
370    if (unfilled.size())
371    {
372        LL_ERRS("LLSDArgsMapper") << _function << " missing required arguments "
373                                  << formatlist(unfilled) << " from " << argsmap << LL_ENDL;
374    }
375
376    // done
377    return args;
378}
379
380std::string LLSDArgsMapper::formatlist(const LLSD& list)
381{
382    std::ostringstream out;
383    const char* delim = "";
384    for (LLSD::array_const_iterator li(list.beginArray()), lend(list.endArray());
385         li != lend; ++li)
386    {
387        out << delim << li->asString();
388        delim = ", ";
389    }
390    return out.str();
391}
392
393LLEventDispatcher::LLEventDispatcher(const std::string& desc, const std::string& key):
394    mDesc(desc),
395    mKey(key)
396{
397}
398
399LLEventDispatcher::~LLEventDispatcher()
400{
401}
402
403/**
404 * DispatchEntry subclass used for callables accepting(const LLSD&)
405 */
406struct LLEventDispatcher::LLSDDispatchEntry: public LLEventDispatcher::DispatchEntry
407{
408    LLSDDispatchEntry(const std::string& desc, const Callable& func, const LLSD& required):
409        DispatchEntry(desc),
410        mFunc(func),
411        mRequired(required)
412    {}
413
414    Callable mFunc;
415    LLSD mRequired;
416
417    virtual void call(const std::string& desc, const LLSD& event) const
418    {
419        // Validate the syntax of the event itself.
420        std::string mismatch(llsd_matches(mRequired, event));
421        if (! mismatch.empty())
422        {
423            LL_ERRS("LLEventDispatcher") << desc << ": bad request: " << mismatch << LL_ENDL;
424        }
425        // Event syntax looks good, go for it!
426        mFunc(event);
427    }
428
429    virtual LLSD addMetadata(LLSD meta) const
430    {
431        meta["required"] = mRequired;
432        return meta;
433    }
434};
435
436/**
437 * DispatchEntry subclass for passing LLSD to functions accepting
438 * arbitrary argument types (convertible via LLSDParam)
439 */
440struct LLEventDispatcher::ParamsDispatchEntry: public LLEventDispatcher::DispatchEntry
441{
442    ParamsDispatchEntry(const std::string& desc, const invoker_function& func):
443        DispatchEntry(desc),
444        mInvoker(func)
445    {}
446
447    invoker_function mInvoker;
448
449    virtual void call(const std::string& desc, const LLSD& event) const
450    {
451        LLSDArgsSource src(desc, event);
452        mInvoker(boost::bind(&LLSDArgsSource::next, boost::ref(src)));
453    }
454};
455
456/**
457 * DispatchEntry subclass for dispatching LLSD::Array to functions accepting
458 * arbitrary argument types (convertible via LLSDParam)
459 */
460struct LLEventDispatcher::ArrayParamsDispatchEntry: public LLEventDispatcher::ParamsDispatchEntry
461{
462    ArrayParamsDispatchEntry(const std::string& desc, const invoker_function& func,
463                             LLSD::Integer arity):
464        ParamsDispatchEntry(desc, func),
465        mArity(arity)
466    {}
467
468    LLSD::Integer mArity;
469
470    virtual LLSD addMetadata(LLSD meta) const
471    {
472        LLSD array(LLSD::emptyArray());
473        // Resize to number of arguments required
474        if (mArity)
475            array[mArity - 1] = LLSD();
476        llassert_always(array.size() == mArity);
477        meta["required"] = array;
478        return meta;
479    }
480};
481
482/**
483 * DispatchEntry subclass for dispatching LLSD::Map to functions accepting
484 * arbitrary argument types (convertible via LLSDParam)
485 */
486struct LLEventDispatcher::MapParamsDispatchEntry: public LLEventDispatcher::ParamsDispatchEntry
487{
488    MapParamsDispatchEntry(const std::string& name, const std::string& desc,
489                           const invoker_function& func,
490                           const LLSD& params, const LLSD& defaults):
491        ParamsDispatchEntry(desc, func),
492        mMapper(name, params, defaults),
493        mRequired(LLSD::emptyMap())
494    {
495        // Build the set of all param keys, then delete the ones that are
496        // optional. What's left are the ones that are required.
497        for (LLSD::array_const_iterator pi(params.beginArray()), pend(params.endArray());
498             pi != pend; ++pi)
499        {
500            mRequired[pi->asString()] = LLSD();
501        }
502
503        if (defaults.isArray() || defaults.isUndefined())
504        {
505            // Right-align the params and defaults arrays.
506            LLSD::Integer offset = params.size() - defaults.size();
507            // Now the name of every defaults[i] is at params[i + offset].
508            for (LLSD::Integer i(0), iend(defaults.size()); i < iend; ++i)
509            {
510                // Erase this optional param from mRequired.
511                mRequired.erase(params[i + offset].asString());
512                // Instead, make an entry in mOptional with the default
513                // param's name and value.
514                mOptional[params[i + offset].asString()] = defaults[i];
515            }
516        }
517        else if (defaults.isMap())
518        {
519            // if defaults is already a map, then it's already in the form we
520            // intend to deliver in metadata
521            mOptional = defaults;
522            // Just delete from mRequired every key appearing in mOptional.
523            for (LLSD::map_const_iterator mi(mOptional.beginMap()), mend(mOptional.endMap());
524                 mi != mend; ++mi)
525            {
526                mRequired.erase(mi->first);
527            }
528        }
529    }
530
531    LLSDArgsMapper mMapper;
532    LLSD mRequired;
533    LLSD mOptional;
534
535    virtual void call(const std::string& desc, const LLSD& event) const
536    {
537        // Just convert from LLSD::Map to LLSD::Array using mMapper, then pass
538        // to base-class call() method.
539        ParamsDispatchEntry::call(desc, mMapper.map(event));
540    }
541
542    virtual LLSD addMetadata(LLSD meta) const
543    {
544        meta["required"] = mRequired;
545        meta["optional"] = mOptional;
546        return meta;
547    }
548};
549
550void LLEventDispatcher::addArrayParamsDispatchEntry(const std::string& name,
551                                                    const std::string& desc,
552                                                    const invoker_function& invoker,
553                                                    LLSD::Integer arity)
554{
555    mDispatch.insert(
556        DispatchMap::value_type(name, DispatchMap::mapped_type(
557                                    new ArrayParamsDispatchEntry(desc, invoker, arity))));
558}
559
560void LLEventDispatcher::addMapParamsDispatchEntry(const std::string& name,
561                                                  const std::string& desc,
562                                                  const invoker_function& invoker,
563                                                  const LLSD& params,
564                                                  const LLSD& defaults)
565{
566    mDispatch.insert(
567        DispatchMap::value_type(name, DispatchMap::mapped_type(
568                                    new MapParamsDispatchEntry(name, desc, invoker, params, defaults))));
569}
570
571/// Register a callable by name
572void LLEventDispatcher::add(const std::string& name, const std::string& desc,
573                            const Callable& callable, const LLSD& required)
574{
575    mDispatch.insert(
576        DispatchMap::value_type(name, DispatchMap::mapped_type(
577                                    new LLSDDispatchEntry(desc, callable, required))));
578}
579
580void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const
581{
582    LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ")::add(" << name
583                                 << "): " << classname << " is not a subclass "
584                                 << "of LLEventDispatcher" << LL_ENDL;
585}
586
587/// Unregister a callable
588bool LLEventDispatcher::remove(const std::string& name)
589{
590    DispatchMap::iterator found = mDispatch.find(name);
591    if (found == mDispatch.end())
592    {
593        return false;
594    }
595    mDispatch.erase(found);
596    return true;
597}
598
599/// Call a registered callable with an explicitly-specified name. If no
600/// such callable exists, die with LL_ERRS.
601void LLEventDispatcher::operator()(const std::string& name, const LLSD& event) const
602{
603    if (! try_call(name, event))
604    {
605        LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): '" << name
606                                     << "' not found" << LL_ENDL;
607    }
608}
609
610/// Extract the @a key value from the incoming @a event, and call the
611/// callable whose name is specified by that map @a key. If no such
612/// callable exists, die with LL_ERRS.
613void LLEventDispatcher::operator()(const LLSD& event) const
614{
615    // This could/should be implemented in terms of the two-arg overload.
616    // However -- we can produce a more informative error message.
617    std::string name(event[mKey]);
618    if (! try_call(name, event))
619    {
620        LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): bad " << mKey
621                                     << " value '" << name << "'" << LL_ENDL;
622    }
623}
624
625bool LLEventDispatcher::try_call(const LLSD& event) const
626{
627    return try_call(event[mKey], event);
628}
629
630bool LLEventDispatcher::try_call(const std::string& name, const LLSD& event) const
631{
632    DispatchMap::const_iterator found = mDispatch.find(name);
633    if (found == mDispatch.end())
634    {
635        return false;
636    }
637    // Found the name, so it's plausible to even attempt the call.
638    found->second->call(STRINGIZE("LLEventDispatcher(" << mDesc << ") calling '" << name << "'"),
639                        event);
640    return true;                    // tell caller we were able to call
641}
642
643LLSD LLEventDispatcher::getMetadata(const std::string& name) const
644{
645    DispatchMap::const_iterator found = mDispatch.find(name);
646    if (found == mDispatch.end())
647    {
648        return LLSD();
649    }
650    LLSD meta;
651    meta["name"] = name;
652    meta["desc"] = found->second->mDesc;
653    return found->second->addMetadata(meta);
654}
655
656LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key):
657    LLEventDispatcher(pumpname, key),
658    mPump(pumpname, true),          // allow tweaking for uniqueness
659    mBoundListener(mPump.listen("self", boost::bind(&LLDispatchListener::process, this, _1)))
660{
661}
662
663bool LLDispatchListener::process(const LLSD& event)
664{
665    (*this)(event);
666    return false;
667}
668
669LLEventDispatcher::DispatchEntry::DispatchEntry(const std::string& desc):
670    mDesc(desc)
671{}
672