a1cd7595e439de535d2df5482aed16feb9ea0e1c
[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         /// Internal
147         struct Creator {
148             static NodeType & create(DirectoryNode & node, std::string const & name, 
149                                      Object const & ob);
150         };
151     };
152
153     /** \brief Config/console tree directory node
154
155         This node type provides the internal and root nodes of the tree. It allows to add arbitrary
156         children and supports directory traversal.
157         
158         Nodes are normally not instantiated manually but are created by the DirectoryNode via
159         mkdir() or add(). Special add() members however allow externally allocated node objects.
160
161         Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
162         managed dynamically, there is a special ObjectDirectory proxy template which provides a
163         DirectoryNode facade. ObjectDirectory is used if a class wants to manage it's own directory
164         as a data member.
165
166         Every node is assigned a (new) name when it is added to a directory. If the directory
167         already has an entry of that name, the name is made unique by appending a suffix of the form
168         '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
169         then uniquified as above. Automatically providing unique names simplifies adding
170         configuration/console support to generic components.
171       */
172     class DirectoryNode : public GenericNode
173     {
174         SENF_LOG_CLASS_AREA();
175         typedef std::map<std::string, GenericNode::ptr> ChildMap;
176     public:
177         ///////////////////////////////////////////////////////////////////////////
178         // Types
179
180         typedef boost::shared_ptr<DirectoryNode> ptr;
181         typedef boost::shared_ptr<DirectoryNode const> cptr;
182         typedef boost::weak_ptr<DirectoryNode> weak_ptr;
183
184         typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
185         typedef ChildMap::const_iterator child_iterator;
186
187         ///////////////////////////////////////////////////////////////////////////
188         ///\name Structors and default members
189         ///\{
190
191         static ptr create();            ///< Create node object.
192                                         /**< You should normally use either mkdir() or
193                                              ObjectDirectory instead of create() */
194
195         ///\}
196         ///////////////////////////////////////////////////////////////////////////
197         ///\name Children
198         ///\{
199
200         template <class NodeType>
201         NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
202                                         ///< Add node to tree
203                                         /**< Adds the \a node to the tree as a child of \a this
204                                              node. The node is given the name \a name. If a node of
205                                              that name already exists, a numeric suffix of the form
206                                              '-n' is added to the name until the name is unique. If
207                                              \a name is empty, it is set to 'unnamed'. */
208
209         template <class Object>
210         typename NodeCreateTraits<Object>::NodeType & add (std::string const & name, 
211                                                            Object const & ob);
212                                         ///< Generic child node factory
213                                         /**< This member is used to create a new child node of the
214                                              current directory. The type of node created depends on
215                                              the type of argument passed.
216
217                                              The node type is selected by the NodeCreateTraits
218                                              class. To allow adding a specific node type, you need
219                                              to provide an overload for
220                                              <tt>senf_console_add_node</tt> which must be visible at
221                                              when you register the new node.
222                                              \code
223                                              MyNodeType & senf_console_add_node(
224                                                  DirectoryNode & dir,
225                                                  std::string const & name,
226                                                  MySpecialObject const & ob,
227                                                  int)
228                                              {
229                                                  return dir.add(name, MyNodeType::create(ob));
230                                              }
231                                              \endcode
232                                              (Do not forget the last unnamed 'int' parameter which
233                                              is not used but serves to disambiguate the
234                                              overloads). */
235
236         GenericNode::ptr remove(std::string const & name);
237                                         ///< Remove node \a name from the tree
238                                         /**< The returned pointer may either be discarded, which
239                                              will automatically dispose the removed node, or it may
240                                              be saved and/or re-attached at some other place in the
241                                              tree. */
242
243         DirectoryNode & operator[](std::string const & name) const;
244                                         ///< Get directory child node
245                                         /**< \throws UnknownNodeNameException if a child \a name
246                                                  does not exist. 
247                                              \throws std::bad_cast if the child \a name is not a
248                                                  directory node. */
249
250         CommandNode & operator()(std::string const & name) const;
251                                         ///< Get command child node
252                                         /**< \throws UnknownNodeNameException if a child \a name
253                                                  does not exist
254                                              \throws std::bad_cast if the child \a name is not a
255                                                  command node. */
256
257         GenericNode & get(std::string const & name) const;
258                                         ///< Get child node
259                                         /**< \throws UnknownNodeNameException if a child \a name
260                                                  does not exist */
261
262         DirectoryNode & mkdir(std::string const & name);
263                                         ///< Create sub-directory node
264         
265         ChildrenRange children() const;
266                                         ///< Return iterator range over all children.
267                                         /**< The returned range is sorted by child name. */
268
269         ///\}
270         ///////////////////////////////////////////////////////////////////////////
271
272         template <class ForwardRange>
273         GenericNode & traverse(ForwardRange const & range);
274                                         ///< Traverse node path starting at this node
275                                         /**< The <tt>FordwareRange::value_type</tt> must be
276                                              (convertible to) std::string. Each range element
277                                              constitutes a step along the node traversal.
278
279                                              If the range starts with an empty element, the
280                                              traversal is started at the root() node, otherwise it
281                                              is started at \a this node. The traversal supports '.',
282                                              '..' and ignores further empty elements. */
283
284         DirectoryNode & doc(std::string const & doc);
285                                         ///< Set node documentation
286
287         ptr thisptr();
288         cptr thisptr() const;
289
290     protected:
291         DirectoryNode();
292
293     private:
294         void add(GenericNode::ptr node);
295         virtual void v_help(std::ostream & output) const;
296
297         ChildMap children_;
298         std::string doc_;
299
300         friend DirectoryNode & root();
301     };
302
303     BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
304
305     /// Exception: Unknown node name
306     struct UnknownNodeNameException : public senf::Exception
307     { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
308
309 #ifndef DOXYGEN
310     template <class Type>
311     struct NodeCreateTraits< boost::shared_ptr<Type> >
312     {};
313 #endif
314
315     /** \brief Config/console tree command node
316
317         The CommandNode is the base-class for the tree leaf nodes. Concrete command node
318         implementations are derived from this class.
319
320         To execute a command, CommandNode::operator()() is called. This abstract virtual function
321         must be implemented in a derived class.
322       */
323     class CommandNode : public GenericNode
324     {
325         SENF_LOG_CLASS_AREA();
326     public:
327         ///////////////////////////////////////////////////////////////////////////
328         // Types
329
330         typedef boost::shared_ptr<CommandNode> ptr;
331         typedef boost::shared_ptr<CommandNode const> cptr;
332         typedef boost::weak_ptr<CommandNode> weak_ptr;
333
334         typedef ParseCommandInfo::ArgumentsRange Arguments;
335
336         ///////////////////////////////////////////////////////////////////////////
337
338         virtual void operator()(std::ostream & output, Arguments const & arguments) = 0;
339                                         ///< Called to execute the command
340                                         /**< \param[in] output stream where result messages may be
341                                                  written to
342                                              \param[in] arguments command arguments. This is a
343                                                  range of ranges of ArgumentToken instances. */
344
345         ptr thisptr();
346         cptr thisptr() const;
347
348     protected:
349         CommandNode();
350
351     private:
352     };
353
354     /** \brief Most simple CommandNode implementation
355
356         This CommandNode implementation simply forwards the \a output and \a arguments arguments to
357         an arbitrary callback.
358       */
359     class SimpleCommandNode : public CommandNode
360     {
361         SENF_LOG_CLASS_AREA();
362     public:
363         ///////////////////////////////////////////////////////////////////////////
364         // Types
365
366         typedef boost::shared_ptr<SimpleCommandNode> ptr;
367         typedef boost::shared_ptr<SimpleCommandNode const> cptr;
368         typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
369
370         typedef boost::function<void (std::ostream &, Arguments const &)> Function;
371
372         ///////////////////////////////////////////////////////////////////////////
373         ///\name Structors and default members
374         ///\{
375
376         static ptr create(Function const & fn);
377
378         ///\}
379         ///////////////////////////////////////////////////////////////////////////
380
381         virtual void operator()(std::ostream & output, Arguments const & arguments);
382
383         ptr thisptr();
384         cptr thisptr() const;
385
386         SimpleCommandNode & doc(std::string const & doc);
387
388     protected:
389         SimpleCommandNode(Function const & fn);
390
391     private:
392         virtual void v_help(std::ostream & output) const;
393
394         Function fn_;
395         std::string doc_;
396     };
397
398 #ifndef DOXYGEN
399     template <class Function>
400     SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name, 
401                                               Function const & fn, ...);
402 #endif
403
404     BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
405
406     DirectoryNode & root();
407
408 }}
409
410 ///////////////////////////////hh.e////////////////////////////////////////
411 #include "Node.cci"
412 #include "Node.ct"
413 #include "Node.cti"
414 #endif
415
416 \f
417 // Local Variables:
418 // mode: c++
419 // fill-column: 100
420 // comment-column: 40
421 // c-file-style: "senf"
422 // indent-tabs-mode: nil
423 // ispell-local-dictionary: "american"
424 // compile-command: "scons -u test"
425 // End: