4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Node public header */
31 /** \defgroup node_tree The node tree
33 The console/config node tree is the central data-structure of the library. Into this tree, all
34 commands and parameters are entered. The tree is then exposed using a file-system like
39 \section console_tree The tree
41 We will start by giving a more complete example. This example contains most of the stuff needed
42 for using the console/config library.
45 // Define callback function.
46 void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command)
49 os << "!! Important message ...\n";
55 // Declare a directory node (proxy) for use by this class. This must be public so we can add
56 // it to the node tree later.
57 senf::console::ScopedDirectory<SomeClass> dir;
59 SomeClass() : dir(this)
61 namespace fty = senf::console::factory;
62 // You may document the directory here or later when adding it to the tree
63 dir.doc("Manager for something");
65 // Add a member function (the pointer-to-member is automatically bound to this instance)
66 dir.add("member", fty::Command(&SomeClass::member, this)
67 .doc("Do the member operation"));
70 void member(std::ostream & os, senf::console::ParseCommandInfo const & command)
78 namespace fty = senf::console::factory;
80 // Provide global documentation
82 .doc("This is someServer server");
84 // Add a new directory to the root and document it. All the mutators return the node object
85 // itself so operations can be chained.
86 senf::console::DirectoryNode & mydir ( senf::console::root()
87 .add("myserver", fty::Directory()
88 .doc("My server specific directory")));
90 // Add a command to that directory
91 mydir.add("mycommand", fty::Command(&mycommand)
92 .doc("mycommand <foo> [<bar>]\n\n"
93 "If <bar> is given, flurgle the <foo>, otherwise burgle it"));
95 // Create a SomeClass instance and add it's directory.
97 mydir.add("someClass", someClass.dir);
99 // Start the interactive console server
100 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
105 \subsection console_nodes Node types
107 The console/config library tree consists of two basic node types:
109 \li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
110 \li senf::console::CommandNode describes a command entry in the tree
111 \li senf::console::LinkNode is a link to another node. It works much like a symlink on POSIX
114 senf::console::CommandNode is the base-class of all command nodes of which there are several,
115 depending on the type of command.
117 There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
118 this node, the tree is traversed.
120 All nodes are allocated on the heap and are managed using a smart pointer.
122 \subsection console_manipulate Manipulating the node tree
124 There are several ways to add nodes to the tree:
126 \li A senf::console::DirectoryNode can be added using senf::console::DirectoryNode::mkdir().
127 \li An arbitrary node can be created and then (possibly later) added to the tree using the
128 corresponding senf::console::DirectoryNode::add() overload.
129 \li A senf::console::CommandNode is normally added to the tree by directly adding a callback
130 using one of the overloaded senf::console::DirectoryNode::add() members. See \ref
132 \li A senf::console::LinkNode is created by senf::console::DirectoryNode::link()
134 When directly adding a node callback, the type of node added depends on the type of
135 callback. The callback types which can be added are listed at \ref console_callbacks.
138 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... }
140 myDirectory.add("foo",fty::Command(&callback));
143 Every node is identified among it's siblings by it's name. The name of the node is set when
144 adding the node to the tree. If the name is empty or non-unique, a unique name will be
145 automatically provided.
147 To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() or the
148 parents senf::console::DirectoryNode::remove() member. This call removes the node from it's
149 parent and returns a (smart) node pointer.
151 \li If you ignore the return value, the node (and it's children) will be deleted.
152 \li Alternatively, you may store away the node and re-attach it later.
153 \li An node (or subtree) can be moved to a different place by unlinking the node at it's old
154 place and re-adding it at it's new location.
155 \li To rename a node, unlink and re-add it with a different name.
158 myDirectory.add("bar", myDirectory.remove("foo"));
161 \subsection console_node_param Assigning additional node parameters
163 Depending on the node type added, additional node parameters may be set. For example, every node
164 has a documentation parameter which is used by the online-help system. To assign these
165 parameters, the node exposes corresponding member functions. Since
166 senf::console::DirectoryNode::add() returns the newly added node by reference. Additional
167 parameters may be added after the factory call:
169 myDirectory.add("foo", fty::Command(&fooCallback).doc("The foo method") );
171 Since the parameter setters all return the node reference, additional parameters may just be
172 added to the end of the command.
174 \subsection console_tree_traverse Traversing the tree
176 The simplest way to access tree elements is to save the return value of the
177 senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
178 the node is not removed. If the node might be removed from the tree, you should use a smart
179 pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.
181 Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
182 '()' have been overloaded in senf::console::DirectoryNode.
184 senf::console::root().getDirectory("myDirectory").getCommand("foo")
185 \\ or more concise but otherwise completely identical
186 senf::console::root()["myDirectory"]("foo")
189 getDirectory and the '[]' operator will return a senf::console::DirectoryNode whereas getCommand
190 and the '()' operator will return a senf::console::CommandNode. If the node is not found or is
191 not of the correct type, an exception will be raised.
193 \section console_object_dir Assigning a directory to an object instance
195 Most objects will register several commands. So it makes sense for these objects to manage their
196 own directory. Since directories are however allocated on the heap, they cannot be directly
197 added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This
198 class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
199 senf::console::DirectoryNode to which all calls are forwarded.
201 The senf::console::ScopedDirectory member should be declared public. This allows the user of the
202 class to add the node to the tree.
205 #ifndef HH_SENF_Scheduler_Console_Node_
206 #define HH_SENF_Scheduler_Console_Node_ 1
210 #include <boost/shared_ptr.hpp>
211 #include <boost/weak_ptr.hpp>
212 #include <boost/enable_shared_from_this.hpp>
213 #include <boost/utility.hpp>
214 #include <boost/range/iterator_range.hpp>
215 #include <boost/any.hpp>
216 #include <senf/Utils/Exception.hh>
217 #include <senf/Utils/Logger/SenfLog.hh>
219 //#include "Node.mpp"
220 //-/////////////////////////////////////////////////////////////////////////////////////////////////
229 namespace detail { struct NodeFactory {}; }
231 /** \brief Get console root node */
232 DirectoryNode & root();
234 /** \brief Dump console directory structure
236 Recursively dumps the console directory structure starting at \a dir. By default, dumps the
237 complete tree beginning at the root node.
239 In contrast to the console 'lr' command, links are dumped by showing the \e absolute path
242 void dump(std::ostream & os, DirectoryNode & dir=root());
244 /** \brief Config/console node tree base-class
246 GenericNode is the base class of all node objects. There are two basic node types derived
247 from GenericNode: DirectoryNode and CommandNode.
249 All nodes are dynamically allocated and automatically managed using reference counting.
251 All nodes are normally linked into a single tree which root node is
252 senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
253 directly (the node has no parent) or indirectly (the node has a parent but is part of an
254 orphaned subtree which is not linked to the root node).
256 Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
257 name is assigned to the node when adding the node to the tree.
262 : public boost::enable_shared_from_this<GenericNode>
264 SENF_LOG_CLASS_AREA();
266 //-////////////////////////////////////////////////////////////////////////
269 typedef boost::shared_ptr<GenericNode> ptr;
270 typedef boost::shared_ptr<GenericNode const> cptr;
271 typedef boost::weak_ptr<GenericNode> weak_ptr;
273 //-////////////////////////////////////////////////////////////////////////
275 virtual ~GenericNode();
277 std::string const & name() const; ///< Node name
278 boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
279 /**< May be null, if the node is the root node or if it is
280 not linked to the tree */
282 std::string path() const; ///< Node path
283 /**< The node path is built by joining the names of all
284 parent nodes with '/' chars. */
285 std::string path(DirectoryNode const & root) const;
286 ///< Node path up to \a root
287 /**< The node path is built by joining the names of all
288 parent nodes up to \a root with '/' chars. */
290 ptr unlink(); ///< Remove node from it's parent directory
291 /**< You may either discard the return value and thereby
292 dispose the node or may re-attach the node at some
293 other place using DirectoryNode::add(). */
295 bool active() const; ///< \c true, if node is attached to the root() node
297 void help(std::ostream & output) const; ///< Write help info to \a output
298 std::string shorthelp() const; ///< Get short (one-line) documentation
300 ptr thisptr(); ///< Get smart pointer to node
301 cptr thisptr() const; ///< Get smart pointer to node (const)
303 bool isChildOf(DirectoryNode & parent) const;
304 ///< \c true, if node is a child of \a parent
305 /**< Will also return \c true, if \a parent is the current
308 bool operator== (GenericNode & other) const;
309 ///< \c true, if this and \a other are the same node
310 bool operator!= (GenericNode & other) const;
311 ///< \c true, if this and \a other are different nodes
313 bool isDirectory() const; ///< \c true, if this is a directory node
314 bool isLink() const; ///< \c true, if this is a link node
315 bool isCommand() const; ///< \c true, if this is a command node
317 GenericNode const & followLink() const; ///< Follow link if \c this node is a link node
318 GenericNode & followLink(); ///< Follow link if \c this node is a link node
323 void name(std::string const & name);
330 virtual void v_help(std::ostream & output) const = 0;
331 ///< Provide help information
332 /**< This member must be implemented in derived classes to
333 provide node specific help information. */
334 virtual std::string v_shorthelp() const = 0;
335 ///< Provide short documentation
336 /**< This member must be implemented in derived classes to
337 provide node specific documentation. */
341 DirectoryNode * parent_;
343 friend class DirectoryNode;
346 /** \brief Config/console tree link node
348 A LinkNode references another node and provides an additional alias name for that node. A
349 LinkNode works like a mixture of UNIX symlinks and hardlinks: It is an explicit link like a
350 UNIX symlink but references another node directly (not via it's path) like a UNIX
351 hardlink. Therefore, a LinkNode works across chroot().
357 //-////////////////////////////////////////////////////////////////////////
360 typedef boost::shared_ptr<LinkNode> ptr;
361 typedef boost::shared_ptr<LinkNode const> cptr;
362 typedef boost::weak_ptr<LinkNode> weak_ptr;
364 //-////////////////////////////////////////////////////////////////////////
365 ///\name Structors and default members
368 static ptr create(GenericNode & node); ///< Create new link node.
369 /**< You should normally use DirectoryNode::link() to
370 create a link node. */
373 //-////////////////////////////////////////////////////////////////////////
375 GenericNode & follow() const; ///< Access the referenced node
380 explicit LinkNode(GenericNode & node);
382 virtual void v_help(std::ostream &) const;
383 virtual std::string v_shorthelp() const;
385 GenericNode::ptr node_;
388 class SimpleCommandNode;
390 /** \brief Config/console tree directory node
392 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
393 children and supports directory traversal.
395 Nodes are normally not instantiated manually but are created using factory calls. Special
396 add() members however allow externally allocated node objects.
398 Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
399 managed dynamically, there is a special ScopedDirectory proxy template which provides a
400 DirectoryNode facade. ScopedDirectory is used if a class wants to manage it's own directory
403 Every node is assigned a (new) name when it is added to a directory. If the directory
404 already has an entry of that name, the name is made unique by appending a suffix of the form
405 '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
406 then uniquified as above. Automatically providing unique names simplifies adding
407 configuration/console support to generic components.
411 class DirectoryNode : public GenericNode
413 SENF_LOG_CLASS_AREA();
414 typedef std::map<std::string, GenericNode::ptr> ChildMap;
416 //-////////////////////////////////////////////////////////////////////////
419 typedef boost::shared_ptr<DirectoryNode> ptr;
420 typedef boost::shared_ptr<DirectoryNode const> cptr;
421 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
423 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
424 typedef ChildMap::const_iterator child_iterator;
426 typedef DirectoryNode node_type;
427 typedef DirectoryNode & return_type;
429 //-////////////////////////////////////////////////////////////////////////
430 ///\name Structors and default members
433 static ptr create(); ///< Create node object.
434 /**< You should normally use either mkdir() or
435 ScopedDirectory instead of create() */
439 //-////////////////////////////////////////////////////////////////////////
443 template <class NodeType>
444 NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
445 ///< Add node to tree
446 /**< Adds the \a node to the tree as a child of \a this
447 node. The node is given the name \a name. If a node of
448 that name already exists, a numeric suffix of the form
449 '-n' is added to the name until the name is unique. If
450 \a name is empty, it is set to 'unnamed'. */
452 template <class NodeType>
453 NodeType & add(std::string const & name, NodeType & node,
454 typename boost::enable_if< boost::is_convertible<NodeType &, GenericNode &> >::type * = 0);
456 template <class Factory>
457 typename Factory::result_type add(std::string const & name, Factory const & factory,
458 typename boost::enable_if< boost::is_convertible<Factory const &, detail::NodeFactory const &> >::type * = 0);
459 ///< Generic child node factory
460 /**< This member is used to create a new child node of the
461 current directory. The type of node created depends on
462 the type of argument passed. */
464 GenericNode::ptr remove(std::string const & name);
465 ///< Remove node \a name from the tree
466 /**< The returned pointer may either be discarded, which
467 will automatically dispose the removed node, or it may
468 be saved and/or re-attached at some other place in the
471 bool hasChild(std::string const & name) const;
472 ///< \c true, if there is a child with name \a name
474 GenericNode & get(std::string const & name) const;
475 ///< Get child node automatically dereferencing links
476 /**< \throws UnknownNodeNameException if a child \a name
478 GenericNode & getLink(std::string const & name) const;
479 ///< Get child node without dereferencing links
480 /**< \throws UnknownNodeNameException if a child \a name
483 DirectoryNode & getDirectory(std::string const & name) const;
484 ///< Get directory child node (dereferencing links)
485 /**< Same as operator[]
486 \throws UnknownNodeNameException if a child \a name
488 \throws std::bad_cast if the child \a name is not a
491 DirectoryNode & operator[](std::string const & name) const;
492 ///< Get directory child node (dereferencing links)
493 /**< Same as getDirectory
494 \throws UnknownNodeNameException if a child \a name
496 \throws std::bad_cast if the child \a name is not a
499 CommandNode & getCommand(std::string const & name) const;
500 ///< Get command child node (dereferencing links)
501 /**< Same as operator()
502 \throws UnknownNodeNameException if a child \a name
504 \throws std::bad_cast if the child \a name is not a
507 CommandNode & operator()(std::string const & name) const;
508 ///< Get command child node (dereferencing links)
509 /**< Same as getCommand()
510 \throws UnknownNodeNameException if a child \a name
512 \throws std::bad_cast if the child \a name is not a
515 ChildrenRange children() const; ///< Return iterator range over all children.
516 /**< The returned range is sorted by child name. */
518 ChildrenRange completions(std::string const & s) const;
519 ///< Return iterator range of completions for \a s
520 /**< The returned range is sorted by child name. */
523 //-////////////////////////////////////////////////////////////////////////
525 DirectoryNode & doc(std::string const & doc); ///< Set node documentation
526 DirectoryNode & shortdoc(std::string const & doc); ///< Set node short documentation
529 cptr thisptr() const;
535 void add(GenericNode::ptr node);
536 virtual void v_help(std::ostream & output) const;
537 virtual std::string v_shorthelp() const;
541 std::string shortdoc_;
543 friend DirectoryNode & root();
546 /// Exception: Unknown node name
547 struct UnknownNodeNameException : public senf::Exception
548 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
550 /** \brief Config/console tree command node
552 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
553 implementations are derived from this class.
555 To execute a command, CommandNode::operator()() or CommandNode::execute() is called.
557 Subclass instances of this node type are automatically created when adding commands to the
558 tree. See \ref console_commands.
562 class CommandNode : public GenericNode
564 SENF_LOG_CLASS_AREA();
566 //-////////////////////////////////////////////////////////////////////////
569 typedef boost::shared_ptr<CommandNode> ptr;
570 typedef boost::shared_ptr<CommandNode const> cptr;
571 typedef boost::weak_ptr<CommandNode> weak_ptr;
573 //-////////////////////////////////////////////////////////////////////////
575 void execute(std::ostream & output, ParseCommandInfo const & command) const;
576 ///< Execute the command
577 /**< \param[in] output stream where result messages may be
579 \param[in] command command arguments. This is a
580 range of ranges of Token instances. */
582 void execute(boost::any & rv, std::ostream & output, ParseCommandInfo const & command)
584 ///< Execute the command
585 /**< \param[out] rv command return value
586 \param[in] output stream where result messages may be
588 \param[in] command command arguments. This is a
589 range of ranges of Token instances. */
591 void operator()(std::ostream & output, ParseCommandInfo const & command) const;
592 ///< Execute the command
593 /**< Same as execute()
594 \param[in] output stream where result messages may be
596 \param[in] command command arguments. This is a
597 range of ranges of Token instances. */
598 void operator()(boost::any & rv, std::ostream & output, ParseCommandInfo const & command)
602 cptr thisptr() const;
610 virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
612 ///< Called to execute the command
613 /**< \param[out] rv return value holder
614 \param[in] os stream where result messages may be
616 \param[in] command command arguments. This is a
617 range of ranges of Token instances. */
622 /** \brief Most simple CommandNode implementation
624 This CommandNode implementation simply forwards the \a output and \a arguments arguments to
625 an arbitrary callback. Thus, it allows to add callbacks with the signature
627 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command)
632 \ingroup console_commands
634 class SimpleCommandNode : public CommandNode
636 SENF_LOG_CLASS_AREA();
638 //-////////////////////////////////////////////////////////////////////////
641 typedef boost::shared_ptr<SimpleCommandNode> ptr;
642 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
643 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
645 typedef boost::function<void (std::ostream &, ParseCommandInfo const &)> Function;
647 typedef SimpleCommandNode node_type;
648 typedef SimpleCommandNode & return_type;
650 //-////////////////////////////////////////////////////////////////////////
651 ///\name Structors and default members
654 static ptr create(Function const & fn);
657 //-////////////////////////////////////////////////////////////////////////
660 cptr thisptr() const;
662 SimpleCommandNode & doc(std::string const & doc);
663 SimpleCommandNode & shortdoc(std::string const & doc);
666 SimpleCommandNode(Function const & fn);
669 virtual void v_help(std::ostream & output) const;
670 virtual std::string v_shorthelp() const;
671 virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
677 std::string shortdoc_;
680 DirectoryNode & provideDirectory(DirectoryNode & dir, std::string const & name);
682 /** \brief Console node factories
684 The senf::console::factory namespace (customarily aliased to \c fty in user code) contains
685 factories used to create new node types:
687 namespace fty = senf::console::factory;
689 senf::console::DirectoryNode & dir (node.add("dirname", fty::Directory()));
691 dir.add("name", fty::Command<void(bool)>(&fn)
693 .doc("documentation"));
696 The node is added by passing the factory instance to senf::console::DirectoryNode::add().
698 To further customize the node, you may call attributor members on the temporary factory class
699 instance. Since the attributor members always return a self-reference to the factory class
700 instance, attributor calls may be chained arbitrarily.
703 \ref console_commands for details on the command nodes \n
704 \ref node_tree for details on the structural nodes (directory, link)
706 \note All factories are documented here as classes when in fact some are functions returning
709 \implementation It is not true, that all attributor members return a self reference. Some
710 attributor members will return a new object of slightly different type. However, the
711 behavior is as documented above.
713 \ingroup console_commands
717 /** \brief SimpleCommandNode factory
719 This factory will create a SimpleCommandNode calling the given callback. A SimpleCommandNode
720 does not support overloading or automatic argument parsing.
722 \attention This class is of interest mostly for testing and as a simple CommandNode
723 example. Use senf::console::factory::Command instead.
726 : public detail::NodeFactory
729 typedef SimpleCommandNode node_type;
730 typedef SimpleCommandNode & result_type;
732 explicit SimpleCommand(SimpleCommandNode::Function fn);
734 SimpleCommand const & doc(std::string const & doc) const;
735 ///< Set simple command documentation
736 SimpleCommand const & shortdoc(std::string const & doc) const;
737 ///< Set simple command short documentation
740 SimpleCommandNode & create(DirectoryNode & dir, std::string const & name) const;
742 SimpleCommandNode::ptr node_;
744 friend class senf::console::DirectoryNode;
747 /** \brief DirectoryNode factory
749 This factory will create new directory nodes. Use
752 namespace fty = senf::console::factory;
753 node.add("mydir", fty::Directory())
756 To add a directory \a mydir to \a node.
761 : public detail::NodeFactory
764 typedef DirectoryNode node_type;
765 typedef DirectoryNode & result_type;
769 Directory const & doc(std::string const & doc) const;
770 ///< Set directory documentation
771 Directory const & shortdoc(std::string const & doc) const;
772 ///< Set directory short documentation
775 DirectoryNode & create(DirectoryNode & dir, std::string const & name) const;
777 DirectoryNode::ptr node_;
779 friend class senf::console::DirectoryNode;
782 /** \brief LinkNode factory
784 This factory will create new link nodes. Use
787 namespace fty = senf::console::factory;
788 node.add("mylink", fty::Link(targetNode))
791 To add a link \a mylink to \a node pointing to \a targetNode
796 : public detail::NodeFactory
799 typedef LinkNode node_type;
800 typedef LinkNode & result_type;
802 explicit Link(GenericNode & target);
805 LinkNode & create(DirectoryNode & dir, std::string const & name) const;
809 friend class senf::console::DirectoryNode;
816 //-/////////////////////////////////////////////////////////////////////////////////////////////////
826 // comment-column: 40
827 // c-file-style: "senf"
828 // indent-tabs-mode: nil
829 // ispell-local-dictionary: "american"
830 // compile-command: "scons -u test"