Fix documentation
[senf.git] / Console / Node.hh
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Node public header */
25
26 /** \defgroup node_tree The console/config file-system node tree
27     
28     The console/config node tree is the central data-structure of the library. Into this tree, all
29     commands and parameters are entered. The tree is then exposed using a file-system like
30     interface.
31     
32     \autotoc
33
34     \section console_tree The tree
35
36     \subsection console_nodes Node types
37
38     The console/config library tree consists of two basic node types:
39     
40     \li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
41     \li senf::console::CommandNode describes a command entry in the tree
42
43     senf::console::CommandNode is the base-class of all command nodes of which there are several,
44     depending on the type of command.
45
46     There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
47     this node, the tree is traversed.
48
49     All nodes are allocated on the heap and are managed using a smart pointer.
50     
51     \subsection console_manipulate Manipulating the node tree
52
53     There are several ways to add nodes to the tree:
54
55     \li A senf::console::DirectoryNode can be added using senf::console::DirectoryNode::mkdir().
56     \li An arbitrary node can be created and then (possibly later) added to the tree using the
57         corresponding senf::console::DirectoryNode::add() overload.
58     \li A senf::console::CommandNode is normally added to the tree by directly adding a callback
59         using one of the overloaded senf::console::DirectoryNode::add() members.
60
61     When directly adding a node callback, the type of node added depends on the type of
62     callback. The callback types which can be added are listed at \ref console_callbacks.
63     
64     \code
65     void callback(std::ostream & os, senf::console::Arguments const & args) { ... }
66     // ...
67     myDirectory.add("foo",&callback);
68     \endcode
69
70     Every node is identified among it's siblings by it's name. The name of the node is set when
71     adding the node to the tree. If the name is empty or non-unique, a unique name will be
72     automatically provided.
73
74     To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink()
75     member. This call removes the node from it's parent and returns a (smart) node pointer.
76
77     \li If you ignore the return value, the node (and it's children) will be deleted.
78     \li Alternatively, you may store away the node and re-attach it later.
79     \li An node (or subtree) can be moved to a different place by unlinking the node at it's old
80         place and re-adding it at it's new location.
81     \li To rename a node, unlink and re-add it with a different name.
82
83     \code
84     myDirectory.add("bar", myDirectory("foo").unlink());
85     \endcode
86
87     \subsection console_node_param Assigning additional node parameters
88
89     Depending on the node type added, additional node parameters may be set. For example, every node
90     has a documentation parameter which is used by the online-help system. To assign these
91     parameters, the node exposes corresponding member functions. Since
92     senf::console::DirectoryNode::add() returns the newly added node by reference, additional
93     parameters may just be added to the end of the add command:
94     \code
95     myDirectory.add("foo",&fooCallback).doc("The foo method");
96     \endcode
97     Since the parameter setters all return the node reference, additional parameters may just be
98     added to the end of the command.
99     
100     \subsection console_tree_traverse Traversing the tree
101
102     The simplest way to access tree elements is to save the return value of the
103     senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
104     the node is not removed. If the node might be removed from the tree, you should use a smart
105     pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.
106
107     Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
108     '()' have been overloaded in senf::console::DirectoryNode.
109     \code
110     senf::console::root()["myDirectory"]("foo")
111     \endcode
112     The '[]' operator will return a senf::console::DirectoryNode whereas '()' will return a
113     senf::console::CommandNode. If the node is not found or is not of the correct type, an exception
114     will be raised.
115
116     \section console_object_dir Assigning a directory to an object instance
117
118     Most objects will register several commands. So it makes sense for these objects to manage their
119     own directory. Since directories are however allocated on the heap, they cannot be directly
120     added to a class. To facilitate this usage, the senf::console::ObjectDirectory is used. This
121     class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
122     senf::console::DirectoryNode to which all calls are forwarded.
123
124     The senf::console::ObjectDirectory member should be declared public. This allows the user of the
125     class to add the node to the tree.
126
127     \section console_long_example Example
128
129     The following is a more complete example. It uses most of the features you will be using from
130     the console library.
131
132     \code
133     // Define callback function.
134     void mycommand(std::ostream & os, senf::console::Arguments const & args)
135     {
136         // ...
137         os << "!! Important message ...\n";
138     }
139
140     class SomeClass
141     {
142     public:
143         // Declare a directory node (proxy) for use by this class. This must be public so we can add
144         // it to the node tree later.
145         senf::console::ObjectDirectory<SomeClass> dir;
146
147         SomeClass() : dir(this) 
148         {
149             // You may document the directory here or later when adding it to the tree
150             dir.doc("Manager for something");
151
152             // Add a member function (the pointer-to-member is automatically bound to this instance)
153             dir.add("member", &SomeClass::member)
154                 .doc("Do the member operation");
155         }
156
157         void member(std::ostream & os, senf::console::Arguments const & args)
158         {
159             // ...
160         }
161     };
162
163     int main(int, char**)
164     {
165         // Provide global documentation
166         senf::console::root()
167             .doc("This is someServer server");
168
169         // Add a new directory to the root and document it. All the mutators return the node object
170         // itself so operations can be chained.
171         senf::console::DirectoryNode & mydir (
172                 .mkdir("myserver")
173                 .doc("My server specific directory"));
174
175         // Add a command to that directory
176         mydir.add("mycommand", &mycommand)
177             .doc("mycommand <foo> [<bar>]\n\n"
178                  "If <bar> is given, flurgle the <foo>, otherwise burgle it");
179
180         // Create a SomeClass instance and add it's directory.
181         SomeClass someClass;
182         mydir.add("someClass", someClass.dir);
183
184         // Start the interactive console server
185         senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
186             .name("someServer");
187     }
188     \endcode
189  */
190
191 #ifndef HH_Node_
192 #define HH_Node_ 1
193
194 // Custom includes
195 #include <map>
196 #include <boost/shared_ptr.hpp>
197 #include <boost/weak_ptr.hpp>
198 #include <boost/enable_shared_from_this.hpp>
199 #include <boost/utility.hpp>
200 #include <boost/range/iterator_range.hpp>
201 #include <boost/typeof/typeof.hpp>
202 #include <boost/type_traits/remove_reference.hpp>
203 #include "../Utils/Exception.hh"
204 #include "../Utils/mpl.hh"
205 #include "../Utils/Logger/SenfLog.hh"
206 #include "Parse.hh"
207
208 //#include "Node.mpp"
209 ///////////////////////////////hh.p////////////////////////////////////////
210
211 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
212
213 namespace senf {
214 namespace console {
215
216     class DirectoryNode;
217     class CommandNode;
218
219     /** \brief Config/console node tree base-class
220
221         GenericNode is the base class of all node objects. There are two basic node types derived
222         from GenericNode:  DirectoryNode and CommandNode.
223
224         All nodes are dynamically allocated and automatically managed using reference counting.
225
226         All nodes are normally linked into a single tree which root node is
227         senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
228         directly (the node has no parent) or indirectly (the node has a parent but is part of an
229         orphaned subtree which is not linked to the root node).
230
231         Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
232         name is assigned to the node when adding the node to the tree.
233
234         \ingroup node_tree
235       */
236     class GenericNode 
237         : public boost::enable_shared_from_this<GenericNode>
238     {
239         SENF_LOG_CLASS_AREA();
240     public:
241         ///////////////////////////////////////////////////////////////////////////
242         // Types
243
244         typedef boost::shared_ptr<GenericNode> ptr;
245         typedef boost::shared_ptr<GenericNode const> cptr;
246         typedef boost::weak_ptr<GenericNode> weak_ptr;
247
248         ///////////////////////////////////////////////////////////////////////////
249
250         virtual ~GenericNode();
251
252         std::string const & name() const; ///< Node name
253         boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
254                                         /**< May be null, if the node is the root node or if it is
255                                              not linked to the tree */
256
257         std::string path() const;       ///< Node path
258                                         /**< The node path is built by joining the names of all
259                                              parent nodes with '/' chars. */
260
261         ptr unlink();                   ///< Remove node from it's parent directory
262                                         /**< You may either discard the return value and thereby
263                                              dispose the node or may re-attach the node at some
264                                              other place using DirectoryNode::add(). */
265
266         bool active() const;            ///< \c true, if node is attached to the root() node
267
268         void help(std::ostream & output) const; /// Write help info to \a output
269
270         ptr thisptr();                  ///< Get smart pointer to node
271         cptr thisptr() const;           ///< Get smart pointer to node (const)
272
273     protected:
274         GenericNode();
275
276         void name(std::string const & name);
277
278 #ifndef DOXYGEN
279     private:
280 #else
281     public:
282 #endif
283         virtual void v_help(std::ostream & output) const = 0;
284                                         ///< Provide help information
285                                         /**< This member must be implemented in derived classes
286                                              to provide node specific help information. */
287
288     private:
289         std::string name_;
290         DirectoryNode * parent_;
291
292         friend class DirectoryNode;
293     };
294
295     class SimpleCommandNode;
296
297     /** \brief Internal: Node creation helper traits
298         
299         This class is used internally to find out the type of node to create for a specific argument
300         type. 
301      */
302     template <class Object>
303     struct NodeCreateTraits
304     {
305         typedef BOOST_TYPEOF_TPL( senf_console_add_node( 
306                                       * static_cast<DirectoryNode *>(0),
307                                       * static_cast<std::string const *>(0),
308                                       * static_cast<Object const *>(0),
309                                       0) ) result_type;
310
311         typedef typename boost::remove_reference<result_type>::type NodeType;
312
313         /// Internal
314         struct Creator {
315             static NodeType & create(DirectoryNode & node, std::string const & name, 
316                                      Object const & ob);
317         };
318     };
319
320     /** \brief Config/console tree directory node
321
322         This node type provides the internal and root nodes of the tree. It allows to add arbitrary
323         children and supports directory traversal.
324         
325         Nodes are normally not instantiated manually but are created by the DirectoryNode via
326         mkdir() or add(). Special add() members however allow externally allocated node objects.
327
328         Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
329         managed dynamically, there is a special ObjectDirectory proxy template which provides a
330         DirectoryNode facade. ObjectDirectory is used if a class wants to manage it's own directory
331         as a data member.
332
333         Every node is assigned a (new) name when it is added to a directory. If the directory
334         already has an entry of that name, the name is made unique by appending a suffix of the form
335         '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
336         then uniquified as above. Automatically providing unique names simplifies adding
337         configuration/console support to generic components.
338
339         \ingroup node_tree
340       */
341     class DirectoryNode : public GenericNode
342     {
343         SENF_LOG_CLASS_AREA();
344         typedef std::map<std::string, GenericNode::ptr> ChildMap;
345     public:
346         ///////////////////////////////////////////////////////////////////////////
347         // Types
348
349         typedef boost::shared_ptr<DirectoryNode> ptr;
350         typedef boost::shared_ptr<DirectoryNode const> cptr;
351         typedef boost::weak_ptr<DirectoryNode> weak_ptr;
352
353         typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
354         typedef ChildMap::const_iterator child_iterator;
355
356         ///////////////////////////////////////////////////////////////////////////
357         ///\name Structors and default members
358         ///\{
359
360         static ptr create();            ///< Create node object.
361                                         /**< You should normally use either mkdir() or
362                                              ObjectDirectory instead of create() */
363
364         ///\}
365         ///////////////////////////////////////////////////////////////////////////
366         ///\name Children
367         ///\{
368
369         template <class NodeType>
370         NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
371                                         ///< Add node to tree
372                                         /**< Adds the \a node to the tree as a child of \a this
373                                              node. The node is given the name \a name. If a node of
374                                              that name already exists, a numeric suffix of the form
375                                              '-n' is added to the name until the name is unique. If
376                                              \a name is empty, it is set to 'unnamed'. */
377
378         template <class Object>
379         typename NodeCreateTraits<Object>::NodeType & add (std::string const & name, 
380                                                            Object const & ob);
381                                         ///< Generic child node factory
382                                         /**< This member is used to create a new child node of the
383                                              current directory. The type of node created depends on
384                                              the type of argument passed.
385
386                                              The node type is selected by the NodeCreateTraits
387                                              class. To allow adding a specific node type, you need
388                                              to provide an overload for
389                                              <tt>senf_console_add_node</tt> which must be visible at
390                                              when you register the new node.
391                                              \code
392                                              MyNodeType & senf_console_add_node(
393                                                  DirectoryNode & dir,
394                                                  std::string const & name,
395                                                  MySpecialObject const & ob,
396                                                  int)
397                                              {
398                                                  return dir.add(name, MyNodeType::create(ob));
399                                              }
400                                              \endcode
401                                              (Do not forget the last unnamed 'int' parameter which
402                                              is not used but serves to disambiguate the
403                                              overloads). */
404
405         GenericNode::ptr remove(std::string const & name);
406                                         ///< Remove node \a name from the tree
407                                         /**< The returned pointer may either be discarded, which
408                                              will automatically dispose the removed node, or it may
409                                              be saved and/or re-attached at some other place in the
410                                              tree. */
411
412         DirectoryNode & operator[](std::string const & name) const;
413                                         ///< Get directory child node
414                                         /**< \throws UnknownNodeNameException if a child \a name
415                                                  does not exist. 
416                                              \throws std::bad_cast if the child \a name is not a
417                                                  directory node. */
418
419         CommandNode & operator()(std::string const & name) const;
420                                         ///< Get command child node
421                                         /**< \throws UnknownNodeNameException if a child \a name
422                                                  does not exist
423                                              \throws std::bad_cast if the child \a name is not a
424                                                  command node. */
425
426         GenericNode & get(std::string const & name) const;
427                                         ///< Get child node
428                                         /**< \throws UnknownNodeNameException if a child \a name
429                                                  does not exist */
430
431         DirectoryNode & mkdir(std::string const & name);
432                                         ///< Create sub-directory node
433         
434         ChildrenRange children() const;
435                                         ///< Return iterator range over all children.
436                                         /**< The returned range is sorted by child name. */
437
438         ///\}
439         ///////////////////////////////////////////////////////////////////////////
440
441         template <class ForwardRange>
442         GenericNode & traverse(ForwardRange const & range);
443                                         ///< Traverse node path starting at this node
444                                         /**< The <tt>FordwareRange::value_type</tt> must be
445                                              (convertible to) std::string. Each range element
446                                              constitutes a step along the node traversal.
447
448                                              If the range starts with an empty element, the
449                                              traversal is started at the root() node, otherwise it
450                                              is started at \a this node. The traversal supports '.',
451                                              '..' and ignores further empty elements. */
452
453         DirectoryNode & doc(std::string const & doc);
454                                         ///< Set node documentation
455
456         ptr thisptr();
457         cptr thisptr() const;
458
459     protected:
460         DirectoryNode();
461
462     private:
463         void add(GenericNode::ptr node);
464         virtual void v_help(std::ostream & output) const;
465
466         ChildMap children_;
467         std::string doc_;
468
469         friend DirectoryNode & root();
470     };
471
472     BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
473
474     /// Exception: Unknown node name
475     struct UnknownNodeNameException : public senf::Exception
476     { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
477
478 #ifndef DOXYGEN
479     template <class Type>
480     struct NodeCreateTraits< boost::shared_ptr<Type> >
481     {};
482 #endif
483
484     /** \brief Config/console tree command node
485
486         The CommandNode is the base-class for the tree leaf nodes. Concrete command node
487         implementations are derived from this class.
488
489         To execute a command, CommandNode::operator()() is called. This abstract virtual function
490         must be implemented in a derived class.
491
492         \ingroup node_tree
493       */
494     class CommandNode : public GenericNode
495     {
496         SENF_LOG_CLASS_AREA();
497     public:
498         ///////////////////////////////////////////////////////////////////////////
499         // Types
500
501         typedef boost::shared_ptr<CommandNode> ptr;
502         typedef boost::shared_ptr<CommandNode const> cptr;
503         typedef boost::weak_ptr<CommandNode> weak_ptr;
504
505         typedef ParseCommandInfo::ArgumentsRange Arguments;
506
507         ///////////////////////////////////////////////////////////////////////////
508
509         virtual void operator()(std::ostream & output, Arguments const & arguments) = 0;
510                                         ///< Called to execute the command
511                                         /**< \param[in] output stream where result messages may be
512                                                  written to
513                                              \param[in] arguments command arguments. This is a
514                                                  range of ranges of ArgumentToken instances. */
515
516         ptr thisptr();
517         cptr thisptr() const;
518
519     protected:
520         CommandNode();
521
522     private:
523     };
524
525     typedef CommandNode::Arguments Arguments;
526
527     /** \brief Most simple CommandNode implementation
528
529         This CommandNode implementation simply forwards the \a output and \a arguments arguments to
530         an arbitrary callback.
531  
532         \ingroup node_tree
533      */
534     class SimpleCommandNode : public CommandNode
535     {
536         SENF_LOG_CLASS_AREA();
537     public:
538         ///////////////////////////////////////////////////////////////////////////
539         // Types
540
541         typedef boost::shared_ptr<SimpleCommandNode> ptr;
542         typedef boost::shared_ptr<SimpleCommandNode const> cptr;
543         typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
544
545         typedef boost::function<void (std::ostream &, Arguments const &)> Function;
546
547         ///////////////////////////////////////////////////////////////////////////
548         ///\name Structors and default members
549         ///\{
550
551         static ptr create(Function const & fn);
552
553         ///\}
554         ///////////////////////////////////////////////////////////////////////////
555
556         virtual void operator()(std::ostream & output, Arguments const & arguments);
557
558         ptr thisptr();
559         cptr thisptr() const;
560
561         SimpleCommandNode & doc(std::string const & doc);
562
563     protected:
564         SimpleCommandNode(Function const & fn);
565
566     private:
567         virtual void v_help(std::ostream & output) const;
568
569         Function fn_;
570         std::string doc_;
571     };
572
573 #ifndef DOXYGEN
574     template <class Function>
575     SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name, 
576                                               Function const & fn, ...);
577 #endif
578
579     BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
580
581     DirectoryNode & root();
582
583 }}
584
585 ///////////////////////////////hh.e////////////////////////////////////////
586 #include "Node.cci"
587 #include "Node.ct"
588 #include "Node.cti"
589 #endif
590
591 \f
592 // Local Variables:
593 // mode: c++
594 // fill-column: 100
595 // comment-column: 40
596 // c-file-style: "senf"
597 // indent-tabs-mode: nil
598 // ispell-local-dictionary: "american"
599 // compile-command: "scons -u test"
600 // End: