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 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 We will start by giving a more complete example. This example contains most of the stuff needed
37 for using the console/config library.
40 // Define callback function.
41 void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command)
44 os << "!! Important message ...\n";
50 // Declare a directory node (proxy) for use by this class. This must be public so we can add
51 // it to the node tree later.
52 senf::console::ScopedDirectory<SomeClass> dir;
54 SomeClass() : dir(this)
56 // You may document the directory here or later when adding it to the tree
57 dir.doc("Manager for something");
59 // Add a member function (the pointer-to-member is automatically bound to this instance)
60 dir.add("member", &SomeClass::member)
61 .doc("Do the member operation");
64 void member(std::ostream & os, senf::console::ParseCommandInfo const & command)
72 // Provide global documentation
74 .doc("This is someServer server");
76 // Add a new directory to the root and document it. All the mutators return the node object
77 // itself so operations can be chained.
78 senf::console::DirectoryNode & mydir (
80 .doc("My server specific directory"));
82 // Add a command to that directory
83 mydir.add("mycommand", &mycommand)
84 .doc("mycommand <foo> [<bar>]\n\n"
85 "If <bar> is given, flurgle the <foo>, otherwise burgle it");
87 // Create a SomeClass instance and add it's directory.
89 mydir.add("someClass", someClass.dir);
91 // Start the interactive console server
92 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
97 \subsection console_nodes Node types
99 The console/config library tree consists of two basic node types:
101 \li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
102 \li senf::console::CommandNode describes a command entry in the tree
103 \li senf::console::LinkNode is a link to another node. It works much like a symlink on POSIX
106 senf::console::CommandNode is the base-class of all command nodes of which there are several,
107 depending on the type of command.
109 There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
110 this node, the tree is traversed.
112 All nodes are allocated on the heap and are managed using a smart pointer.
114 \subsection console_manipulate Manipulating the node tree
116 There are several ways to add nodes to the tree:
118 \li A senf::console::DirectoryNode can be added using senf::console::DirectoryNode::mkdir().
119 \li An arbitrary node can be created and then (possibly later) added to the tree using the
120 corresponding senf::console::DirectoryNode::add() overload.
121 \li A senf::console::CommandNode is normally added to the tree by directly adding a callback
122 using one of the overloaded senf::console::DirectoryNode::add() members. See \ref
124 \li A senf::console::LinkNode is created by senf::console::DirectoryNode::link()
126 When directly adding a node callback, the type of node added depends on the type of
127 callback. The callback types which can be added are listed at \ref console_callbacks.
130 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... }
132 myDirectory.add("foo",&callback);
135 Every node is identified among it's siblings by it's name. The name of the node is set when
136 adding the node to the tree. If the name is empty or non-unique, a unique name will be
137 automatically provided.
139 To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() or the
140 parents senf::console::DirectoryNode::remove() member. This call removes the node from it's
141 parent and returns a (smart) node pointer.
143 \li If you ignore the return value, the node (and it's children) will be deleted.
144 \li Alternatively, you may store away the node and re-attach it later.
145 \li An node (or subtree) can be moved to a different place by unlinking the node at it's old
146 place and re-adding it at it's new location.
147 \li To rename a node, unlink and re-add it with a different name.
150 myDirectory.add("bar", myDirectory.remove("foo"));
153 \subsection console_node_param Assigning additional node parameters
155 Depending on the node type added, additional node parameters may be set. For example, every node
156 has a documentation parameter which is used by the online-help system. To assign these
157 parameters, the node exposes corresponding member functions. Since
158 senf::console::DirectoryNode::add() returns the newly added node by reference, additional
159 parameters may just be added to the end of the add command:
161 myDirectory.add("foo",&fooCallback).doc("The foo method");
163 Since the parameter setters all return the node reference, additional parameters may just be
164 added to the end of the command.
166 \subsection console_tree_traverse Traversing the tree
168 The simplest way to access tree elements is to save the return value of the
169 senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
170 the node is not removed. If the node might be removed from the tree, you should use a smart
171 pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.
173 Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
174 '()' have been overloaded in senf::console::DirectoryNode.
176 senf::console::root().getDirectory("myDirectory").getCommand("foo")
177 \\ or more concise but otherwise completely identical
178 senf::console::root()["myDirectory"]("foo")
181 getDirectory and the '[]' operator will return a senf::console::DirectoryNode whereas getCommand
182 and the '()' operator will return a senf::console::CommandNode. If the node is not found or is
183 not of the correct type, an exception will be raised.
185 \section console_object_dir Assigning a directory to an object instance
187 Most objects will register several commands. So it makes sense for these objects to manage their
188 own directory. Since directories are however allocated on the heap, they cannot be directly
189 added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This
190 class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
191 senf::console::DirectoryNode to which all calls are forwarded.
193 The senf::console::ScopedDirectory member should be declared public. This allows the user of the
194 class to add the node to the tree.
197 #ifndef HH_SENF_Scheduler_Console_Node_
198 #define HH_SENF_Scheduler_Console_Node_ 1
202 #include <boost/shared_ptr.hpp>
203 #include <boost/weak_ptr.hpp>
204 #include <boost/enable_shared_from_this.hpp>
205 #include <boost/utility.hpp>
206 #include <boost/range/iterator_range.hpp>
207 #include <boost/typeof/typeof.hpp>
208 #include <boost/type_traits/remove_reference.hpp>
209 #include <boost/any.hpp>
210 #include "../../Utils/Exception.hh"
211 #include "../../Utils/mpl.hh"
212 #include "../../Utils/Logger/SenfLog.hh"
213 #include "../../Utils/type_traits.hh"
216 //#include "Node.mpp"
217 ///////////////////////////////hh.p////////////////////////////////////////
226 DirectoryNode & root();
227 void dump(std::ostream & os, DirectoryNode & dir=root());
229 /** \brief Config/console node tree base-class
231 GenericNode is the base class of all node objects. There are two basic node types derived
232 from GenericNode: DirectoryNode and CommandNode.
234 All nodes are dynamically allocated and automatically managed using reference counting.
236 All nodes are normally linked into a single tree which root node is
237 senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
238 directly (the node has no parent) or indirectly (the node has a parent but is part of an
239 orphaned subtree which is not linked to the root node).
241 Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
242 name is assigned to the node when adding the node to the tree.
247 : public boost::enable_shared_from_this<GenericNode>
249 SENF_LOG_CLASS_AREA();
251 ///////////////////////////////////////////////////////////////////////////
254 typedef boost::shared_ptr<GenericNode> ptr;
255 typedef boost::shared_ptr<GenericNode const> cptr;
256 typedef boost::weak_ptr<GenericNode> weak_ptr;
258 ///////////////////////////////////////////////////////////////////////////
260 virtual ~GenericNode();
262 std::string const & name() const; ///< Node name
263 boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
264 /**< May be null, if the node is the root node or if it is
265 not linked to the tree */
267 std::string path() const; ///< Node path
268 /**< The node path is built by joining the names of all
269 parent nodes with '/' chars. */
270 std::string path(DirectoryNode const & root) const;
271 ///< Node path up to \a root
272 /**< The node path is built by joining the names of all
273 parent nodes up to \a root with '/' chars. */
275 ptr unlink(); ///< Remove node from it's parent directory
276 /**< You may either discard the return value and thereby
277 dispose the node or may re-attach the node at some
278 other place using DirectoryNode::add(). */
280 bool active() const; ///< \c true, if node is attached to the root() node
282 void help(std::ostream & output) const; ///< Write help info to \a output
283 std::string shorthelp() const; ///< Get short (one-line) documentation
285 ptr thisptr(); ///< Get smart pointer to node
286 cptr thisptr() const; ///< Get smart pointer to node (const)
288 bool isChildOf(DirectoryNode & parent) const;
289 ///< \c true, if node is a child of \a parent
290 /**< Will also return \c true, if \a parent is the current
293 bool operator== (GenericNode & other) const;
294 ///< \c true, if this and \a other are the same node
295 bool operator!= (GenericNode & other) const;
296 ///< \c true, if this and \a other are different nodes
298 bool isDirectory() const; ///< \c true, if this is a directory node
299 bool isLink() const; ///< \c true, if this is a link node
300 bool isCommand() const; ///< \c true, if this is a command node
302 GenericNode const & followLink() const; ///< Follow link if \c this node is a link node
303 GenericNode & followLink(); ///< Follow link if \c this node is a link node
308 void name(std::string const & name);
315 virtual void v_help(std::ostream & output) const = 0;
316 ///< Provide help information
317 /**< This member must be implemented in derived classes to
318 provide node specific help information. */
319 virtual std::string v_shorthelp() const = 0;
320 ///< Provide short documentation
321 /**< This member must be implemented in derived classes to
322 provide node specific documentation. */
326 DirectoryNode * parent_;
328 friend class DirectoryNode;
331 /** \brief Config/console tree link node
333 A LinkNode references another node and provides an additional alias name for that node. A
334 LinkNode works like a mixture of UNIX symlinks and hardlinks: It is an explicit link like a
335 UNIX symlink but references another node directly (not via it's path) like a UNIX
336 hardlink. Therefore, a LinkNode works across chroot().
342 ///////////////////////////////////////////////////////////////////////////
345 typedef boost::shared_ptr<LinkNode> ptr;
346 typedef boost::shared_ptr<LinkNode const> cptr;
347 typedef boost::weak_ptr<LinkNode> weak_ptr;
349 ///////////////////////////////////////////////////////////////////////////
350 ///\name Structors and default members
353 static ptr create(GenericNode & node); ///< Create new link node.
354 /**< You should normally use DirectoryNode::link() to
355 create a link node. */
358 ///////////////////////////////////////////////////////////////////////////
360 GenericNode & follow() const; ///< Access the referenced node
365 explicit LinkNode(GenericNode & node);
367 virtual void v_help(std::ostream &) const;
368 virtual std::string v_shorthelp() const;
370 GenericNode::ptr node_;
373 class SimpleCommandNode;
375 /** \brief Internal: Node creation helper traits
377 This class is used internally to find out the type of node to create for a specific argument
380 template <class Object>
381 struct NodeCreateTraits
383 typedef BOOST_TYPEOF_TPL( senf_console_add_node(
384 * static_cast<DirectoryNode *>(0),
385 * static_cast<std::string const *>(0),
386 * static_cast<Object *>(0),
388 typedef typename senf::remove_cvref<base_type>::type value_type;
390 typedef typename value_type::node_type NodeType;
391 typedef typename value_type::return_type result_type;
395 static result_type create(DirectoryNode & node, std::string const & name,
400 /** \brief Config/console tree directory node
402 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
403 children and supports directory traversal.
405 Nodes are normally not instantiated manually but are created by the DirectoryNode via
406 mkdir() or add(). Special add() members however allow externally allocated node objects.
408 Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
409 managed dynamically, there is a special ScopedDirectory proxy template which provides a
410 DirectoryNode facade. ScopedDirectory is used if a class wants to manage it's own directory
413 Every node is assigned a (new) name when it is added to a directory. If the directory
414 already has an entry of that name, the name is made unique by appending a suffix of the form
415 '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
416 then uniquified as above. Automatically providing unique names simplifies adding
417 configuration/console support to generic components.
421 class DirectoryNode : public GenericNode
423 SENF_LOG_CLASS_AREA();
424 typedef std::map<std::string, GenericNode::ptr> ChildMap;
426 ///////////////////////////////////////////////////////////////////////////
429 typedef boost::shared_ptr<DirectoryNode> ptr;
430 typedef boost::shared_ptr<DirectoryNode const> cptr;
431 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
433 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
434 typedef ChildMap::const_iterator child_iterator;
436 typedef DirectoryNode node_type;
437 typedef DirectoryNode & return_type;
439 ///////////////////////////////////////////////////////////////////////////
440 ///\name Structors and default members
443 static ptr create(); ///< Create node object.
444 /**< You should normally use either mkdir() or
445 ScopedDirectory instead of create() */
449 ///////////////////////////////////////////////////////////////////////////
453 template <class NodeType>
454 NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
455 ///< Add node to tree
456 /**< Adds the \a node to the tree as a child of \a this
457 node. The node is given the name \a name. If a node of
458 that name already exists, a numeric suffix of the form
459 '-n' is added to the name until the name is unique. If
460 \a name is empty, it is set to 'unnamed'. */
462 template <class Object>
463 typename NodeCreateTraits<Object>::result_type add(std::string const & name,
465 ///< Generic child node factory
466 /**< This member is used to create a new child node of the
467 current directory. The type of node created depends on
468 the type of argument passed.
470 The node type is selected by the NodeCreateTraits
471 class. To allow adding a specific node type, you need
472 to provide an overload for
473 <tt>senf_console_add_node</tt> which must be visible at
474 when you register the new node.
476 MyNodeType & senf_console_add_node(
478 std::string const & name,
479 MySpecialObject const & ob,
482 return dir.add(name, MyNodeType::create(ob));
485 (Do not forget the last unnamed 'int' parameter which
486 is not used but serves to disambiguate the
489 template <class Object>
490 typename NodeCreateTraits<Object>::result_type add(std::string const & name,
492 ///< Generic child node factory
495 GenericNode::ptr remove(std::string const & name);
496 ///< Remove node \a name from the tree
497 /**< The returned pointer may either be discarded, which
498 will automatically dispose the removed node, or it may
499 be saved and/or re-attached at some other place in the
502 bool hasChild(std::string const & name) const;
503 ///< \c true, if there is a child with name \a name
505 GenericNode & get(std::string const & name) const;
506 ///< Get child node automatically dereferencing links
507 /**< \throws UnknownNodeNameException if a child \a name
509 GenericNode & getLink(std::string const & name) const;
510 ///< Get child node without dereferencing links
511 /**< \throws UnknownNodeNameException if a child \a name
514 DirectoryNode & getDirectory(std::string const & name) const;
515 ///< Get directory child node (dereferencing links)
516 /**< Same as operator[]
517 \throws UnknownNodeNameException if a child \a name
519 \throws std::bad_cast if the child \a name is not a
522 DirectoryNode & operator[](std::string const & name) const;
523 ///< Get directory child node (dereferencing links)
524 /**< Same as getDirectory
525 \throws UnknownNodeNameException if a child \a name
527 \throws std::bad_cast if the child \a name is not a
530 CommandNode & getCommand(std::string const & name) const;
531 ///< Get command child node (dereferencing links)
532 /**< Same as operator()
533 \throws UnknownNodeNameException if a child \a name
535 \throws std::bad_cast if the child \a name is not a
538 CommandNode & operator()(std::string const & name) const;
539 ///< Get command child node (dereferencing links)
540 /**< Same as getCommand()
541 \throws UnknownNodeNameException if a child \a name
543 \throws std::bad_cast if the child \a name is not a
546 DirectoryNode & mkdir(std::string const & name);
547 ///< Create sub-directory node
548 DirectoryNode & provideDirectory(std::string const & name);
549 ///< Return subdirectory, possibly creating it
551 ChildrenRange children() const; ///< Return iterator range over all children.
552 /**< The returned range is sorted by child name. */
554 ChildrenRange completions(std::string const & s) const;
555 ///< Return iterator range of completions for \a s
556 /**< The returned range is sorted by child name. */
558 void link(std::string const & name, GenericNode & target);
559 ///< Create a child node which is a link to target. \a s
560 /**< The new link node will be a child of the node for which this member function is called. */
563 ///////////////////////////////////////////////////////////////////////////
565 DirectoryNode & doc(std::string const & doc); ///< Set node documentation
566 DirectoryNode & shortdoc(std::string const & doc); ///< Set node short documentation
569 cptr thisptr() const;
575 void add(GenericNode::ptr node);
576 virtual void v_help(std::ostream & output) const;
577 virtual std::string v_shorthelp() const;
581 std::string shortdoc_;
583 friend DirectoryNode & root();
586 /// Exception: Unknown node name
587 struct UnknownNodeNameException : public senf::Exception
588 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
591 template <class Type>
592 struct NodeCreateTraits< boost::shared_ptr<Type> >
596 /** \brief Config/console tree command node
598 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
599 implementations are derived from this class.
601 To execute a command, CommandNode::operator()() or CommandNode::execute() is called.
603 Subclass instances of this node type are automatically created when adding commands to the
604 tree. See \ref console_commands.
608 class CommandNode : public GenericNode
610 SENF_LOG_CLASS_AREA();
612 ///////////////////////////////////////////////////////////////////////////
615 typedef boost::shared_ptr<CommandNode> ptr;
616 typedef boost::shared_ptr<CommandNode const> cptr;
617 typedef boost::weak_ptr<CommandNode> weak_ptr;
619 ///////////////////////////////////////////////////////////////////////////
621 void execute(std::ostream & output, ParseCommandInfo const & command) const;
622 ///< Execute the command
623 /**< \param[in] output stream where result messages may be
625 \param[in] arguments command arguments. This is a
626 range of ranges of Token instances. */
628 void execute(boost::any & rv, std::ostream & output, ParseCommandInfo const & command)
630 ///< Execute the command
631 /**< \param[out] rv command return value
632 \param[in] output stream where result messages may be
634 \param[in] arguments command arguments. This is a
635 range of ranges of Token instances. */
637 void operator()(std::ostream & output, ParseCommandInfo const & command) const;
638 ///< Execute the command
639 /**< Same as execute()
640 \param[in] output stream where result messages may be
642 \param[in] arguments command arguments. This is a
643 range of ranges of Token instances. */
644 void operator()(boost::any & rv, std::ostream & output, ParseCommandInfo const & command)
648 cptr thisptr() const;
656 virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
658 ///< Called to execute the command
659 /**< \param[out] rv return value holder
660 \param[in] arguments command arguments. This is a
661 range of ranges of Token instances. */
666 /** \brief Most simple CommandNode implementation
668 This CommandNode implementation simply forwards the \a output and \a arguments arguments to
669 an arbitrary callback. Thus, it allows to add callbacks with the signature
671 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command)
676 \ingroup console_commands
678 class SimpleCommandNode : public CommandNode
680 SENF_LOG_CLASS_AREA();
682 ///////////////////////////////////////////////////////////////////////////
685 typedef boost::shared_ptr<SimpleCommandNode> ptr;
686 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
687 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
689 typedef boost::function<void (std::ostream &, ParseCommandInfo const &)> Function;
691 typedef SimpleCommandNode node_type;
692 typedef SimpleCommandNode & return_type;
694 ///////////////////////////////////////////////////////////////////////////
695 ///\name Structors and default members
698 static ptr create(Function const & fn);
701 ///////////////////////////////////////////////////////////////////////////
704 cptr thisptr() const;
706 SimpleCommandNode & doc(std::string const & doc);
707 SimpleCommandNode & shortdoc(std::string const & doc);
710 SimpleCommandNode(Function const & fn);
713 virtual void v_help(std::ostream & output) const;
714 virtual std::string v_shorthelp() const;
715 virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
721 std::string shortdoc_;
726 SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name,
727 SimpleCommandNode::Function fn, int);
729 DirectoryNode & senf_console_add_node(DirectoryNode & node, std::string const & name,
730 DirectoryNode & dir, int);
736 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
738 BOOST_TYPEOF_REGISTER_TYPE(senf::console::DirectoryNode)
739 BOOST_TYPEOF_REGISTER_TYPE(senf::console::SimpleCommandNode)
742 ///////////////////////////////hh.e////////////////////////////////////////
752 // comment-column: 40
753 // c-file-style: "senf"
754 // indent-tabs-mode: nil
755 // ispell-local-dictionary: "american"
756 // compile-command: "scons -u test"