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 namespace fty = senf::console::factory;
57 // You may document the directory here or later when adding it to the tree
58 dir.doc("Manager for something");
60 // Add a member function (the pointer-to-member is automatically bound to this instance)
61 dir.add("member", fty::Command(this, &SomeClass::member)
62 .doc("Do the member operation"));
65 void member(std::ostream & os, senf::console::ParseCommandInfo const & command)
73 namespace fty = senf::console::factory;
75 // Provide global documentation
77 .doc("This is someServer server");
79 // Add a new directory to the root and document it. All the mutators return the node object
80 // itself so operations can be chained.
81 senf::console::DirectoryNode & mydir ( senf::console::root()
82 .add("myserver", fty::Directory()
83 .doc("My server specific directory")));
85 // Add a command to that directory
86 mydir.add("mycommand", fty::Command(&mycommand)
87 .doc("mycommand <foo> [<bar>]\n\n"
88 "If <bar> is given, flurgle the <foo>, otherwise burgle it"));
90 // Create a SomeClass instance and add it's directory.
92 mydir.add("someClass", someClass.dir);
94 // Start the interactive console server
95 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
100 \subsection console_nodes Node types
102 The console/config library tree consists of two basic node types:
104 \li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
105 \li senf::console::CommandNode describes a command entry in the tree
106 \li senf::console::LinkNode is a link to another node. It works much like a symlink on POSIX
109 senf::console::CommandNode is the base-class of all command nodes of which there are several,
110 depending on the type of command.
112 There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
113 this node, the tree is traversed.
115 All nodes are allocated on the heap and are managed using a smart pointer.
117 \subsection console_manipulate Manipulating the node tree
119 There are several ways to add nodes to the tree:
121 \li A senf::console::DirectoryNode can be added using senf::console::DirectoryNode::mkdir().
122 \li An arbitrary node can be created and then (possibly later) added to the tree using the
123 corresponding senf::console::DirectoryNode::add() overload.
124 \li A senf::console::CommandNode is normally added to the tree by directly adding a callback
125 using one of the overloaded senf::console::DirectoryNode::add() members. See \ref
127 \li A senf::console::LinkNode is created by senf::console::DirectoryNode::link()
129 When directly adding a node callback, the type of node added depends on the type of
130 callback. The callback types which can be added are listed at \ref console_callbacks.
133 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... }
135 myDirectory.add("foo",&callback);
138 Every node is identified among it's siblings by it's name. The name of the node is set when
139 adding the node to the tree. If the name is empty or non-unique, a unique name will be
140 automatically provided.
142 To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() or the
143 parents senf::console::DirectoryNode::remove() member. This call removes the node from it's
144 parent and returns a (smart) node pointer.
146 \li If you ignore the return value, the node (and it's children) will be deleted.
147 \li Alternatively, you may store away the node and re-attach it later.
148 \li An node (or subtree) can be moved to a different place by unlinking the node at it's old
149 place and re-adding it at it's new location.
150 \li To rename a node, unlink and re-add it with a different name.
153 myDirectory.add("bar", myDirectory.remove("foo"));
156 \subsection console_node_param Assigning additional node parameters
158 Depending on the node type added, additional node parameters may be set. For example, every node
159 has a documentation parameter which is used by the online-help system. To assign these
160 parameters, the node exposes corresponding member functions. Since
161 senf::console::DirectoryNode::add() returns the newly added node by reference, additional
162 parameters may just be added to the end of the add command:
164 myDirectory.add("foo",&fooCallback).doc("The foo method");
166 Since the parameter setters all return the node reference, additional parameters may just be
167 added to the end of the command.
169 \subsection console_tree_traverse Traversing the tree
171 The simplest way to access tree elements is to save the return value of the
172 senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
173 the node is not removed. If the node might be removed from the tree, you should use a smart
174 pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.
176 Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
177 '()' have been overloaded in senf::console::DirectoryNode.
179 senf::console::root().getDirectory("myDirectory").getCommand("foo")
180 \\ or more concise but otherwise completely identical
181 senf::console::root()["myDirectory"]("foo")
184 getDirectory and the '[]' operator will return a senf::console::DirectoryNode whereas getCommand
185 and the '()' operator will return a senf::console::CommandNode. If the node is not found or is
186 not of the correct type, an exception will be raised.
188 \section console_object_dir Assigning a directory to an object instance
190 Most objects will register several commands. So it makes sense for these objects to manage their
191 own directory. Since directories are however allocated on the heap, they cannot be directly
192 added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This
193 class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
194 senf::console::DirectoryNode to which all calls are forwarded.
196 The senf::console::ScopedDirectory member should be declared public. This allows the user of the
197 class to add the node to the tree.
200 #ifndef HH_SENF_Scheduler_Console_Node_
201 #define HH_SENF_Scheduler_Console_Node_ 1
205 #include <boost/shared_ptr.hpp>
206 #include <boost/weak_ptr.hpp>
207 #include <boost/enable_shared_from_this.hpp>
208 #include <boost/utility.hpp>
209 #include <boost/range/iterator_range.hpp>
210 #include <boost/any.hpp>
211 #include <senf/Utils/Exception.hh>
212 #include <senf/Utils/mpl.hh>
213 #include <senf/Utils/Logger/SenfLog.hh>
214 #include <senf/Utils/type_traits.hh>
217 //#include "Node.mpp"
218 ///////////////////////////////hh.p////////////////////////////////////////
227 namespace detail { struct NodeFactory {}; }
229 /** \brief Get console root node */
230 DirectoryNode & root();
232 /** \brief Dump console directory structure
234 Recursively dumps the console directory structure starting at \a dir. By default, dumps the
235 complete tree beginning at the root node.
237 In contrast to the console 'lr' command, links are dumped by showing the \e absolute path
240 void dump(std::ostream & os, DirectoryNode & dir=root());
242 /** \brief Config/console node tree base-class
244 GenericNode is the base class of all node objects. There are two basic node types derived
245 from GenericNode: DirectoryNode and CommandNode.
247 All nodes are dynamically allocated and automatically managed using reference counting.
249 All nodes are normally linked into a single tree which root node is
250 senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
251 directly (the node has no parent) or indirectly (the node has a parent but is part of an
252 orphaned subtree which is not linked to the root node).
254 Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
255 name is assigned to the node when adding the node to the tree.
260 : public boost::enable_shared_from_this<GenericNode>
262 SENF_LOG_CLASS_AREA();
264 ///////////////////////////////////////////////////////////////////////////
267 typedef boost::shared_ptr<GenericNode> ptr;
268 typedef boost::shared_ptr<GenericNode const> cptr;
269 typedef boost::weak_ptr<GenericNode> weak_ptr;
271 ///////////////////////////////////////////////////////////////////////////
273 virtual ~GenericNode();
275 std::string const & name() const; ///< Node name
276 boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
277 /**< May be null, if the node is the root node or if it is
278 not linked to the tree */
280 std::string path() const; ///< Node path
281 /**< The node path is built by joining the names of all
282 parent nodes with '/' chars. */
283 std::string path(DirectoryNode const & root) const;
284 ///< Node path up to \a root
285 /**< The node path is built by joining the names of all
286 parent nodes up to \a root with '/' chars. */
288 ptr unlink(); ///< Remove node from it's parent directory
289 /**< You may either discard the return value and thereby
290 dispose the node or may re-attach the node at some
291 other place using DirectoryNode::add(). */
293 bool active() const; ///< \c true, if node is attached to the root() node
295 void help(std::ostream & output) const; ///< Write help info to \a output
296 std::string shorthelp() const; ///< Get short (one-line) documentation
298 ptr thisptr(); ///< Get smart pointer to node
299 cptr thisptr() const; ///< Get smart pointer to node (const)
301 bool isChildOf(DirectoryNode & parent) const;
302 ///< \c true, if node is a child of \a parent
303 /**< Will also return \c true, if \a parent is the current
306 bool operator== (GenericNode & other) const;
307 ///< \c true, if this and \a other are the same node
308 bool operator!= (GenericNode & other) const;
309 ///< \c true, if this and \a other are different nodes
311 bool isDirectory() const; ///< \c true, if this is a directory node
312 bool isLink() const; ///< \c true, if this is a link node
313 bool isCommand() const; ///< \c true, if this is a command node
315 GenericNode const & followLink() const; ///< Follow link if \c this node is a link node
316 GenericNode & followLink(); ///< Follow link if \c this node is a link node
321 void name(std::string const & name);
328 virtual void v_help(std::ostream & output) const = 0;
329 ///< Provide help information
330 /**< This member must be implemented in derived classes to
331 provide node specific help information. */
332 virtual std::string v_shorthelp() const = 0;
333 ///< Provide short documentation
334 /**< This member must be implemented in derived classes to
335 provide node specific documentation. */
339 DirectoryNode * parent_;
341 friend class DirectoryNode;
344 /** \brief Config/console tree link node
346 A LinkNode references another node and provides an additional alias name for that node. A
347 LinkNode works like a mixture of UNIX symlinks and hardlinks: It is an explicit link like a
348 UNIX symlink but references another node directly (not via it's path) like a UNIX
349 hardlink. Therefore, a LinkNode works across chroot().
355 ///////////////////////////////////////////////////////////////////////////
358 typedef boost::shared_ptr<LinkNode> ptr;
359 typedef boost::shared_ptr<LinkNode const> cptr;
360 typedef boost::weak_ptr<LinkNode> weak_ptr;
362 ///////////////////////////////////////////////////////////////////////////
363 ///\name Structors and default members
366 static ptr create(GenericNode & node); ///< Create new link node.
367 /**< You should normally use DirectoryNode::link() to
368 create a link node. */
371 ///////////////////////////////////////////////////////////////////////////
373 GenericNode & follow() const; ///< Access the referenced node
378 explicit LinkNode(GenericNode & node);
380 virtual void v_help(std::ostream &) const;
381 virtual std::string v_shorthelp() const;
383 GenericNode::ptr node_;
386 class SimpleCommandNode;
388 /** \brief Config/console tree directory node
390 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
391 children and supports directory traversal.
393 Nodes are normally not instantiated manually but are created by the DirectoryNode via
394 mkdir() or add(). Special add() members however allow externally allocated node objects.
396 Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
397 managed dynamically, there is a special ScopedDirectory proxy template which provides a
398 DirectoryNode facade. ScopedDirectory is used if a class wants to manage it's own directory
401 Every node is assigned a (new) name when it is added to a directory. If the directory
402 already has an entry of that name, the name is made unique by appending a suffix of the form
403 '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
404 then uniquified as above. Automatically providing unique names simplifies adding
405 configuration/console support to generic components.
409 class DirectoryNode : public GenericNode
411 SENF_LOG_CLASS_AREA();
412 typedef std::map<std::string, GenericNode::ptr> ChildMap;
414 ///////////////////////////////////////////////////////////////////////////
417 typedef boost::shared_ptr<DirectoryNode> ptr;
418 typedef boost::shared_ptr<DirectoryNode const> cptr;
419 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
421 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
422 typedef ChildMap::const_iterator child_iterator;
424 typedef DirectoryNode node_type;
425 typedef DirectoryNode & return_type;
427 ///////////////////////////////////////////////////////////////////////////
428 ///\name Structors and default members
431 static ptr create(); ///< Create node object.
432 /**< You should normally use either mkdir() or
433 ScopedDirectory instead of create() */
437 ///////////////////////////////////////////////////////////////////////////
441 template <class NodeType>
442 NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
443 ///< Add node to tree
444 /**< Adds the \a node to the tree as a child of \a this
445 node. The node is given the name \a name. If a node of
446 that name already exists, a numeric suffix of the form
447 '-n' is added to the name until the name is unique. If
448 \a name is empty, it is set to 'unnamed'. */
450 template <class NodeType>
451 NodeType & add(std::string const & name, NodeType & node,
452 typename boost::enable_if< boost::is_convertible<NodeType &, GenericNode &> >::type * = 0);
454 template <class Factory>
455 typename Factory::result_type add(std::string const & name, Factory const & factory,
456 typename boost::enable_if< boost::is_convertible<Factory const &, detail::NodeFactory const &> >::type * = 0);
457 ///< Generic child node factory
458 /**< This member is used to create a new child node of the
459 current directory. The type of node created depends on
460 the type of argument passed. */
462 GenericNode::ptr remove(std::string const & name);
463 ///< Remove node \a name from the tree
464 /**< The returned pointer may either be discarded, which
465 will automatically dispose the removed node, or it may
466 be saved and/or re-attached at some other place in the
469 bool hasChild(std::string const & name) const;
470 ///< \c true, if there is a child with name \a name
472 GenericNode & get(std::string const & name) const;
473 ///< Get child node automatically dereferencing links
474 /**< \throws UnknownNodeNameException if a child \a name
476 GenericNode & getLink(std::string const & name) const;
477 ///< Get child node without dereferencing links
478 /**< \throws UnknownNodeNameException if a child \a name
481 DirectoryNode & getDirectory(std::string const & name) const;
482 ///< Get directory child node (dereferencing links)
483 /**< Same as operator[]
484 \throws UnknownNodeNameException if a child \a name
486 \throws std::bad_cast if the child \a name is not a
489 DirectoryNode & operator[](std::string const & name) const;
490 ///< Get directory child node (dereferencing links)
491 /**< Same as getDirectory
492 \throws UnknownNodeNameException if a child \a name
494 \throws std::bad_cast if the child \a name is not a
497 CommandNode & getCommand(std::string const & name) const;
498 ///< Get command child node (dereferencing links)
499 /**< Same as operator()
500 \throws UnknownNodeNameException if a child \a name
502 \throws std::bad_cast if the child \a name is not a
505 CommandNode & operator()(std::string const & name) const;
506 ///< Get command child node (dereferencing links)
507 /**< Same as getCommand()
508 \throws UnknownNodeNameException if a child \a name
510 \throws std::bad_cast if the child \a name is not a
513 ChildrenRange children() const; ///< Return iterator range over all children.
514 /**< The returned range is sorted by child name. */
516 ChildrenRange completions(std::string const & s) const;
517 ///< Return iterator range of completions for \a s
518 /**< The returned range is sorted by child name. */
521 ///////////////////////////////////////////////////////////////////////////
523 DirectoryNode & doc(std::string const & doc); ///< Set node documentation
524 DirectoryNode & shortdoc(std::string const & doc); ///< Set node short documentation
527 cptr thisptr() const;
533 void add(GenericNode::ptr node);
534 virtual void v_help(std::ostream & output) const;
535 virtual std::string v_shorthelp() const;
539 std::string shortdoc_;
541 friend DirectoryNode & root();
544 /// Exception: Unknown node name
545 struct UnknownNodeNameException : public senf::Exception
546 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
548 /** \brief Config/console tree command node
550 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
551 implementations are derived from this class.
553 To execute a command, CommandNode::operator()() or CommandNode::execute() is called.
555 Subclass instances of this node type are automatically created when adding commands to the
556 tree. See \ref console_commands.
560 class CommandNode : public GenericNode
562 SENF_LOG_CLASS_AREA();
564 ///////////////////////////////////////////////////////////////////////////
567 typedef boost::shared_ptr<CommandNode> ptr;
568 typedef boost::shared_ptr<CommandNode const> cptr;
569 typedef boost::weak_ptr<CommandNode> weak_ptr;
571 ///////////////////////////////////////////////////////////////////////////
573 void execute(std::ostream & output, ParseCommandInfo const & command) const;
574 ///< Execute the command
575 /**< \param[in] output stream where result messages may be
577 \param[in] command command arguments. This is a
578 range of ranges of Token instances. */
580 void execute(boost::any & rv, std::ostream & output, ParseCommandInfo const & command)
582 ///< Execute the command
583 /**< \param[out] rv command return value
584 \param[in] output stream where result messages may be
586 \param[in] command command arguments. This is a
587 range of ranges of Token instances. */
589 void operator()(std::ostream & output, ParseCommandInfo const & command) const;
590 ///< Execute the command
591 /**< Same as execute()
592 \param[in] output stream where result messages may be
594 \param[in] command command arguments. This is a
595 range of ranges of Token instances. */
596 void operator()(boost::any & rv, std::ostream & output, ParseCommandInfo const & command)
600 cptr thisptr() const;
608 virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
610 ///< Called to execute the command
611 /**< \param[out] rv return value holder
612 \param[in] os stream where result messages may be
614 \param[in] command command arguments. This is a
615 range of ranges of Token instances. */
620 /** \brief Most simple CommandNode implementation
622 This CommandNode implementation simply forwards the \a output and \a arguments arguments to
623 an arbitrary callback. Thus, it allows to add callbacks with the signature
625 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command)
630 \ingroup console_commands
632 class SimpleCommandNode : public CommandNode
634 SENF_LOG_CLASS_AREA();
636 ///////////////////////////////////////////////////////////////////////////
639 typedef boost::shared_ptr<SimpleCommandNode> ptr;
640 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
641 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
643 typedef boost::function<void (std::ostream &, ParseCommandInfo const &)> Function;
645 typedef SimpleCommandNode node_type;
646 typedef SimpleCommandNode & return_type;
648 ///////////////////////////////////////////////////////////////////////////
649 ///\name Structors and default members
652 static ptr create(Function const & fn);
655 ///////////////////////////////////////////////////////////////////////////
658 cptr thisptr() const;
660 SimpleCommandNode & doc(std::string const & doc);
661 SimpleCommandNode & shortdoc(std::string const & doc);
664 SimpleCommandNode(Function const & fn);
667 virtual void v_help(std::ostream & output) const;
668 virtual std::string v_shorthelp() const;
669 virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
675 std::string shortdoc_;
678 DirectoryNode & provideDirectory(DirectoryNode & dir, std::string const & name);
685 : public detail::NodeFactory
688 typedef SimpleCommandNode node_type;
689 typedef SimpleCommandNode & result_type;
691 explicit SimpleCommand(SimpleCommandNode::Function fn);
693 SimpleCommandNode & create(DirectoryNode & dir, std::string const & name) const;
695 SimpleCommand const & doc(std::string const & doc) const;
696 SimpleCommand const & shortdoc(std::string const & doc) const;
699 SimpleCommandNode::ptr node_;
703 : public detail::NodeFactory
706 typedef DirectoryNode node_type;
707 typedef DirectoryNode & result_type;
711 DirectoryNode & create(DirectoryNode & dir, std::string const & name) const;
713 Directory const & doc(std::string const & doc) const;
714 Directory const & shortdoc(std::string const & doc) const;
717 DirectoryNode::ptr node_;
721 : public detail::NodeFactory
724 typedef LinkNode node_type;
725 typedef LinkNode & result_type;
727 explicit Link(GenericNode & target);
729 LinkNode & create(DirectoryNode & dir, std::string const & name) const;
741 ///////////////////////////////hh.e////////////////////////////////////////
751 // comment-column: 40
752 // c-file-style: "senf"
753 // indent-tabs-mode: nil
754 // ispell-local-dictionary: "american"
755 // compile-command: "scons -u test"