Console: Add lots of 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 #ifndef HH_Node_
27 #define HH_Node_ 1
28
29 // Custom includes
30 #include <map>
31 #include <boost/shared_ptr.hpp>
32 #include <boost/weak_ptr.hpp>
33 #include <boost/enable_shared_from_this.hpp>
34 #include <boost/utility.hpp>
35 #include <boost/range/iterator_range.hpp>
36 #include <boost/typeof/typeof.hpp>
37 #include <boost/type_traits/remove_reference.hpp>
38 #include "../Utils/Exception.hh"
39 #include "../Utils/mpl.hh"
40 #include "../Utils/Logger/SenfLog.hh"
41 #include "Parse.hh"
42
43 //#include "Node.mpp"
44 ///////////////////////////////hh.p////////////////////////////////////////
45
46 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
47
48 namespace senf {
49 namespace console {
50
51     class DirectoryNode;
52     class CommandNode;
53
54     /** \brief Config/console node tree base-class
55
56         GenericNode is the base class of all node objects. There are two basic node types derived
57         from GenericNode:  DirectoryNode and CommandNode.
58
59         All nodes are dynamically allocated and automatically managed using reference counting.
60
61         All nodes are normally linked into a single tree which root node is
62         senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
63         directly (the node has no parent) or indirectly (the node has a parent but is part of an
64         orphaned subtree which is not linked to the root node).
65
66         Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
67         name is assigned to the node when adding the node to the tree.
68       */
69     class GenericNode 
70         : public boost::enable_shared_from_this<GenericNode>
71     {
72         SENF_LOG_CLASS_AREA();
73     public:
74         ///////////////////////////////////////////////////////////////////////////
75         // Types
76
77         typedef boost::shared_ptr<GenericNode> ptr;
78         typedef boost::shared_ptr<GenericNode const> cptr;
79         typedef boost::weak_ptr<GenericNode> weak_ptr;
80
81         ///////////////////////////////////////////////////////////////////////////
82
83         virtual ~GenericNode();
84
85         std::string const & name() const; ///< Node name
86         boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
87                                         /**< May be null, if the node is the root node or if it is
88                                              not linked to the tree */
89
90         std::string path() const;       ///< Node path
91                                         /**< The node path is built by joining the names of all
92                                              parent nodes with '/' chars. */
93
94         ptr unlink();                   ///< Remove node from it's parent directory
95                                         /**< You may either discard the return value and thereby
96                                              dispose the node or may re-attach the node at some
97                                              other place using DirectoryNode::add(). */
98
99         bool active() const;            ///< \c true, if node is attached to the root() node
100
101         void help(std::ostream & output) const; /// Write help info to \a output
102
103         ptr thisptr();                  ///< Get smart pointer to node
104         cptr thisptr() const;           ///< Get smart pointer to node (const)
105
106     protected:
107         GenericNode();
108
109         void name(std::string const & name);
110
111 #ifndef DOXYGEN
112     private:
113 #else
114     public:
115 #endif
116         virtual void v_help(std::ostream & output) const = 0;
117                                         ///< Provide help information
118                                         /**< This member must be implemented in derived classes
119                                              to provide node specific help information. */
120
121     private:
122         std::string name_;
123         DirectoryNode * parent_;
124
125         friend class DirectoryNode;
126     };
127
128     class SimpleCommandNode;
129
130     /** \brief Internal: Node creation helper traits
131         
132         This class is used internally to find out the type of node to create for a specific argument
133         type. 
134      */
135     template <class Object>
136     struct NodeCreateTraits
137     {
138         typedef BOOST_TYPEOF_TPL( senf_console_add_node( 
139                                       * static_cast<DirectoryNode *>(0),
140                                       * static_cast<std::string const *>(0),
141                                       * static_cast<Object const *>(0),
142                                       0) ) result_type;
143
144         typedef typename boost::remove_reference<result_type>::type NodeType;
145
146         struct Creator {
147             static NodeType & create(DirectoryNode & node, std::string const & name, 
148                                      Object const & ob);
149         };
150     };
151
152     /** \brief Config/console tree directory node
153
154         This node type provides the internal and root nodes of the tree. It allows to add arbitrary
155         children and supports directory traversal.
156         
157         Nodes are normally not instantiated manually but are created by the DirectoryNode via
158         mkdir() or add(). Special add() members however allow externally allocated node objects.
159
160         Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
161         managed dynamically, there is a special ObjectDirectory proxy template which provides a
162         DirectoryNode facade. ObjectDirectory is used if a class wants to manage it's own directory
163         as a data member.
164
165         Every node is assigned a (new) name when it is added to a directory. If the directory
166         already has an entry of that name, the name is made unique by appending a suffix of the form
167         '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
168         then uniquified as above. Automatically providing unique names simplifies adding
169         configuration/console support to generic components.
170       */
171     class DirectoryNode : public GenericNode
172     {
173         SENF_LOG_CLASS_AREA();
174         typedef std::map<std::string, GenericNode::ptr> ChildMap;
175     public:
176         ///////////////////////////////////////////////////////////////////////////
177         // Types
178
179         typedef boost::shared_ptr<DirectoryNode> ptr;
180         typedef boost::shared_ptr<DirectoryNode const> cptr;
181         typedef boost::weak_ptr<DirectoryNode> weak_ptr;
182
183         typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
184         typedef ChildMap::const_iterator child_iterator;
185
186         ///////////////////////////////////////////////////////////////////////////
187         ///\name Structors and default members
188         ///\{
189
190         static ptr create();            ///< Create node object.
191                                         /**< You should normally use either mkdir() or
192                                              ObjectDirectory instead of create() */
193
194         ///\}
195         ///////////////////////////////////////////////////////////////////////////
196         ///\name Children
197         ///\{
198
199         template <class NodeType>
200         NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
201                                         ///< Add node to tree
202                                         /**< Adds the \a node to the tree as a child of \a this
203                                              node. The node is given the name \a name. If a node of
204                                              that name already exists, a numeric suffix of the form
205                                              '-n' is added to the name until the name is unique. If
206                                              \a name is empty, it is set to 'unnamed'. */
207
208         template <class Object>
209         typename NodeCreateTraits<Object>::NodeType & add (std::string const & name, 
210                                                            Object const & ob);
211                                         ///< Generic child node factory
212                                         /**< This member is used to create a new child node of the
213                                              current directory. The type of node created depends on
214                                              the type of argument passed.
215
216                                              The node type is selected by the NodeCreateTraits
217                                              class. To allow adding a specific node type, you need
218                                              to provide an overload for
219                                              <tt>senf_console_add_node</tt> which must be visible at
220                                              when you register the new node.
221                                              \code
222                                              MyNodeType & senf_console_add_node(
223                                                  DirectoryNode & dir,
224                                                  std::string const & name,
225                                                  MySpecialObject const & ob,
226                                                  int)
227                                              {
228                                                  return dir.add(name, MyNodeType::create(ob));
229                                              }
230                                              \endcode
231                                              (Do not forget the last unnamed 'int' parameter which
232                                              is not used but serves to disambiguate the
233                                              overloads). */
234
235         GenericNode::ptr remove(std::string const & name);
236                                         ///< Remove node \a name from the tree
237                                         /**< The returned pointer may either be discarded, which
238                                              will automatically dispose the removed node, or it may
239                                              be saved and/or re-attached at some other place in the
240                                              tree. */
241
242         DirectoryNode & operator[](std::string const & name) const;
243                                         ///< Get directory child node
244                                         /**< \throws UnknownNodeNameException if a child \a name
245                                                  does not exist. 
246                                              \throws std::bad_cast if the child \a name is not a
247                                                  directory node. */
248
249         CommandNode & operator()(std::string const & name) const;
250                                         ///< Get command child node
251                                         /**< \throws UnknownNodeNameException if a child \a name
252                                                  does not exist
253                                              \throws std::bad_cast if the child \a name is not a
254                                                  command node. */
255
256         GenericNode & get(std::string const & name) const;
257                                         ///< Get child node
258                                         /**< \throws UnknownNodeNameException if a child \a name
259                                                  does not exist */
260
261         DirectoryNode & mkdir(std::string const & name);
262                                         ///< Create sub-directory node
263         
264         ChildrenRange children() const;
265                                         ///< Return iterator range over all children.
266                                         /**< The returned range is sorted by child name. */
267
268         ///\}
269         ///////////////////////////////////////////////////////////////////////////
270
271         template <class ForwardRange>
272         GenericNode & traverse(ForwardRange const & range);
273                                         ///< Traverse node path starting at this node
274                                         /**< The <tt>FordwareRange::value_type</tt> must be
275                                              (convertible to) std::string. Each range element
276                                              constitutes a step along the node traversal.
277
278                                              If the range starts with an empty element, the
279                                              traversal is started at the root() node, otherwise it
280                                              is started at \a this node. The traversal supports '.',
281                                              '..' and ignores further empty elements. */
282
283         DirectoryNode & doc(std::string const & doc);
284                                         ///< Set node documentation
285
286         ptr thisptr();
287         cptr thisptr() const;
288
289     protected:
290         DirectoryNode();
291
292     private:
293         void add(GenericNode::ptr node);
294         virtual void v_help(std::ostream & output) const;
295
296         ChildMap children_;
297         std::string doc_;
298
299         friend DirectoryNode & root();
300     };
301
302     BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
303
304     /// Exception: Unknown node name
305     struct UnknownNodeNameException : public senf::Exception
306     { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
307
308 #ifndef DOXYGEN
309     template <class Type>
310     struct NodeCreateTraits< boost::shared_ptr<Type> >
311     {};
312 #endif
313
314     /** \brief Config/console tree command node
315
316         The CommandNode is the base-class for the tree leaf nodes. Concrete command node
317         implementations are derived from this class.
318
319         To execute a command, CommandNode::operator()() is called. This abstract virtual function
320         must be implemented in a derived class.
321       */
322     class CommandNode : public GenericNode
323     {
324         SENF_LOG_CLASS_AREA();
325     public:
326         ///////////////////////////////////////////////////////////////////////////
327         // Types
328
329         typedef boost::shared_ptr<CommandNode> ptr;
330         typedef boost::shared_ptr<CommandNode const> cptr;
331         typedef boost::weak_ptr<CommandNode> weak_ptr;
332
333         typedef ParseCommandInfo::ArgumentsRange Arguments;
334
335         ///////////////////////////////////////////////////////////////////////////
336
337         virtual void operator()(std::ostream & output, Arguments const & arguments) = 0;
338                                         ///< Called to execute the command
339                                         /**< \param[in] output stream where result messages may be
340                                                  written to
341                                              \param[in] arguments command arguments. This is a
342                                                  range of ranges of ArgumentToken instances. */
343
344         ptr thisptr();
345         cptr thisptr() const;
346
347     protected:
348         CommandNode();
349
350     private:
351     };
352
353     /** \brief Most simple CommandNode implementation
354
355         This CommandNode implementation simply forwards the \a output and \a arguments arguments to
356         an arbitrary callback.
357       */
358     class SimpleCommandNode : public CommandNode
359     {
360         SENF_LOG_CLASS_AREA();
361     public:
362         ///////////////////////////////////////////////////////////////////////////
363         // Types
364
365         typedef boost::shared_ptr<SimpleCommandNode> ptr;
366         typedef boost::shared_ptr<SimpleCommandNode const> cptr;
367         typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
368
369         typedef boost::function<void (std::ostream &, Arguments const &)> Function;
370
371         ///////////////////////////////////////////////////////////////////////////
372
373         virtual void operator()(std::ostream & output, Arguments const & arguments);
374
375         ptr thisptr();
376         cptr thisptr() const;
377
378         static ptr create(Function const & fn);
379
380         SimpleCommandNode & doc(std::string const & doc);
381
382     protected:
383         SimpleCommandNode(Function const & fn);
384
385     private:
386         virtual void v_help(std::ostream & output) const;
387
388         Function fn_;
389         std::string doc_;
390     };
391
392 #ifndef DOXYGEN
393     template <class Function>
394     SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name, 
395                                               Function const & fn, ...);
396 #endif
397
398     BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
399
400     DirectoryNode & root();
401
402 }}
403
404 ///////////////////////////////hh.e////////////////////////////////////////
405 #include "Node.cci"
406 #include "Node.ct"
407 #include "Node.cti"
408 #endif
409
410 \f
411 // Local Variables:
412 // mode: c++
413 // fill-column: 100
414 // comment-column: 40
415 // c-file-style: "senf"
416 // indent-tabs-mode: nil
417 // ispell-local-dictionary: "american"
418 // compile-command: "scons -u test"
419 // End: