4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief Node public header */
26 /** \defgroup node_tree The console/config file-system node tree
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
34 \section console_tree The tree
36 \subsection console_nodes Node types
38 The console/config library tree consists of two basic node types:
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
43 senf::console::CommandNode is the base-class of all command nodes of which there are several,
44 depending on the type of command.
46 There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
47 this node, the tree is traversed.
49 All nodes are allocated on the heap and are managed using a smart pointer.
51 \subsection console_manipulate Manipulating the node tree
53 There are several ways to add nodes to the tree:
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.
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.
65 void callback(std::ostream & os, senf::console::Arguments const & args) { ... }
67 myDirectory.add("foo",&callback);
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.
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.
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.
84 myDirectory.add("bar", myDirectory("foo").unlink());
87 \subsection console_node_param Assigning additional node parameters
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:
95 myDirectory.add("foo",&fooCallback).doc("The foo method");
97 Since the parameter setters all return the node reference, additional parameters may just be
98 added to the end of the command.
100 \subsection console_tree_traverse Traversing the tree
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.
107 Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
108 '()' have been overloaded in senf::console::DirectoryNode.
110 senf::console::root()["myDirectory"]("foo")
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
116 \section console_object_dir Assigning a directory to an object instance
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.
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.
127 \section console_long_example Example
129 The following is a more complete example. It uses most of the features you will be using from
133 // Define callback function.
134 void mycommand(std::ostream & os, senf::console::Arguments const & args)
137 os << "!! Important message ...\n";
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;
147 SomeClass() : dir(this)
149 // You may document the directory here or later when adding it to the tree
150 dir.doc("Manager for something");
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");
157 void member(std::ostream & os, senf::console::Arguments const & args)
163 int main(int, char**)
165 // Provide global documentation
166 senf::console::root()
167 .doc("This is someServer server");
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 (
173 .doc("My server specific directory"));
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");
180 // Create a SomeClass instance and add it's directory.
182 mydir.add("someClass", someClass.dir);
184 // Start the interactive console server
185 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
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"
208 //#include "Node.mpp"
209 ///////////////////////////////hh.p////////////////////////////////////////
211 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
219 /** \brief Config/console node tree base-class
221 GenericNode is the base class of all node objects. There are two basic node types derived
222 from GenericNode: DirectoryNode and CommandNode.
224 All nodes are dynamically allocated and automatically managed using reference counting.
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).
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.
237 : public boost::enable_shared_from_this<GenericNode>
239 SENF_LOG_CLASS_AREA();
241 ///////////////////////////////////////////////////////////////////////////
244 typedef boost::shared_ptr<GenericNode> ptr;
245 typedef boost::shared_ptr<GenericNode const> cptr;
246 typedef boost::weak_ptr<GenericNode> weak_ptr;
248 ///////////////////////////////////////////////////////////////////////////
250 virtual ~GenericNode();
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 */
257 std::string path() const; ///< Node path
258 /**< The node path is built by joining the names of all
259 parent nodes with '/' chars. */
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(). */
266 bool active() const; ///< \c true, if node is attached to the root() node
268 void help(std::ostream & output) const; /// Write help info to \a output
270 ptr thisptr(); ///< Get smart pointer to node
271 cptr thisptr() const; ///< Get smart pointer to node (const)
276 void name(std::string const & name);
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. */
290 DirectoryNode * parent_;
292 friend class DirectoryNode;
295 class SimpleCommandNode;
297 /** \brief Internal: Node creation helper traits
299 This class is used internally to find out the type of node to create for a specific argument
302 template <class Object>
303 struct NodeCreateTraits
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),
311 typedef typename boost::remove_reference<result_type>::type NodeType;
315 static NodeType & create(DirectoryNode & node, std::string const & name,
320 /** \brief Config/console tree directory node
322 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
323 children and supports directory traversal.
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.
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
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.
341 class DirectoryNode : public GenericNode
343 SENF_LOG_CLASS_AREA();
344 typedef std::map<std::string, GenericNode::ptr> ChildMap;
346 ///////////////////////////////////////////////////////////////////////////
349 typedef boost::shared_ptr<DirectoryNode> ptr;
350 typedef boost::shared_ptr<DirectoryNode const> cptr;
351 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
353 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
354 typedef ChildMap::const_iterator child_iterator;
356 ///////////////////////////////////////////////////////////////////////////
357 ///\name Structors and default members
360 static ptr create(); ///< Create node object.
361 /**< You should normally use either mkdir() or
362 ObjectDirectory instead of create() */
365 ///////////////////////////////////////////////////////////////////////////
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'. */
378 template <class Object>
379 typename NodeCreateTraits<Object>::NodeType & add (std::string const & name,
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.
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.
392 MyNodeType & senf_console_add_node(
394 std::string const & name,
395 MySpecialObject const & ob,
398 return dir.add(name, MyNodeType::create(ob));
401 (Do not forget the last unnamed 'int' parameter which
402 is not used but serves to disambiguate the
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
412 DirectoryNode & operator[](std::string const & name) const;
413 ///< Get directory child node
414 /**< \throws UnknownNodeNameException if a child \a name
416 \throws std::bad_cast if the child \a name is not a
419 CommandNode & operator()(std::string const & name) const;
420 ///< Get command child node
421 /**< \throws UnknownNodeNameException if a child \a name
423 \throws std::bad_cast if the child \a name is not a
426 GenericNode & get(std::string const & name) const;
428 /**< \throws UnknownNodeNameException if a child \a name
431 DirectoryNode & mkdir(std::string const & name);
432 ///< Create sub-directory node
434 ChildrenRange children() const;
435 ///< Return iterator range over all children.
436 /**< The returned range is sorted by child name. */
439 ///////////////////////////////////////////////////////////////////////////
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.
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. */
453 DirectoryNode & doc(std::string const & doc);
454 ///< Set node documentation
457 cptr thisptr() const;
463 void add(GenericNode::ptr node);
464 virtual void v_help(std::ostream & output) const;
469 friend DirectoryNode & root();
472 BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
474 /// Exception: Unknown node name
475 struct UnknownNodeNameException : public senf::Exception
476 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
479 template <class Type>
480 struct NodeCreateTraits< boost::shared_ptr<Type> >
484 /** \brief Config/console tree command node
486 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
487 implementations are derived from this class.
489 To execute a command, CommandNode::operator()() is called. This abstract virtual function
490 must be implemented in a derived class.
494 class CommandNode : public GenericNode
496 SENF_LOG_CLASS_AREA();
498 ///////////////////////////////////////////////////////////////////////////
501 typedef boost::shared_ptr<CommandNode> ptr;
502 typedef boost::shared_ptr<CommandNode const> cptr;
503 typedef boost::weak_ptr<CommandNode> weak_ptr;
505 typedef ParseCommandInfo::ArgumentsRange Arguments;
507 ///////////////////////////////////////////////////////////////////////////
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
513 \param[in] arguments command arguments. This is a
514 range of ranges of ArgumentToken instances. */
517 cptr thisptr() const;
525 typedef CommandNode::Arguments Arguments;
527 /** \brief Most simple CommandNode implementation
529 This CommandNode implementation simply forwards the \a output and \a arguments arguments to
530 an arbitrary callback.
534 class SimpleCommandNode : public CommandNode
536 SENF_LOG_CLASS_AREA();
538 ///////////////////////////////////////////////////////////////////////////
541 typedef boost::shared_ptr<SimpleCommandNode> ptr;
542 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
543 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
545 typedef boost::function<void (std::ostream &, Arguments const &)> Function;
547 ///////////////////////////////////////////////////////////////////////////
548 ///\name Structors and default members
551 static ptr create(Function const & fn);
554 ///////////////////////////////////////////////////////////////////////////
556 virtual void operator()(std::ostream & output, Arguments const & arguments);
559 cptr thisptr() const;
561 SimpleCommandNode & doc(std::string const & doc);
564 SimpleCommandNode(Function const & fn);
567 virtual void v_help(std::ostream & output) const;
574 template <class Function>
575 SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name,
576 Function const & fn, ...);
579 BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
581 DirectoryNode & root();
585 ///////////////////////////////hh.e////////////////////////////////////////
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"