User Manual, Developers Guide and API Documentation

wns::node Namespace Reference

Basic building blocks for a simulation : The Node. More...


Classes

class  Interface
 Interface of Node. More...
class  Node
 Contains various Components to form a network element in a simulation. More...
class  NodeSimulationModel

Namespaces

namespace  component
namespace  tests

Typedefs

typedef
wns::container::Registry
< std::string, node::Interface * > 
Registry


Detailed Description

A simulation consists of a number of Nodes (Node), which are communicating with each other. As a simple example consider two Nodes (Node), a Server (WebServer) and a Client (WebBrowser):

inline_dotgraph_10.dot

Each node contains several components that enable communication. In this example components are WiMAX, IP, TCP, Webserver, WebBrowser. Before we continue we will define what we mean when talking about nodes and components:

Node

Component

The component semantics have been borrowed from UML 2.0. In "The Unified Modeling Language Reference Manual, Second Edition" Rumbaugh et.al. state that a component is

"A modular part of a system design that hides its implementation behind a set of external interfaces. Within a a system, components satisfying the same interfaces may be substituted freely."

This is in accordance with our understanding of a component. In particular we have the following specializations:

A node is only little more than a container for components. The minimal (but very useless) component only has a parent node and a name. It does not offer or require any services. However, a component that does not do anything is not very usefull. Therefore components realize services. These services are realized by depending on other services that are offered by other components (remember ISO/OSI?). How these services look like is out of scope of the component concept. The only requirement on all components is that they implement the component::findOtherComponents method which is called after all components within a node have been created. Here the component needs to find its required services (details see below). But now back to the interesting stuff:

The nodes (Node) are communicating via TCP/IP over WiMAX (802.16). Packets will be generated in either WebBrowser or WebServer Component and will travel down the node through the TCP, IP and WiMAX Component in order to be sent to the other Node where they travel the Node up again. The question is now: How to achieve such a setup? What do the config files look like and what are the respective classes in the C++ world?

To simplify the example a little further we're going to focus on TCP and IP only. First of all let's have a look how the TCP and the IP Component are going to exchange information/data.

inline_dotgraph_11.dot

For our example the TCP and IP are going to form a Node. How can we do that? Have a look at the following code snippet:

00001 
00002 node::Interface* node = new Node(registry, nodeConfig);
00003 component::Interface* ci = new component::tests::ComponentStub(node, "component");
00004 component::tests::TCPInterface* tcp =
00005     new component::tests::TCP(ci, tcpConfig);
00006 component::tests::IPInterface* ip =
00007     new component::tests::IP(ci, ipConfig);
00008 
00009 node->addService(tcp->getName(), tcp);
00010 node->addService(ip->getName(), ip);

First we're creating a Node (node) and two components (tcp, ip). After that we're putting the two components into the Node. The node contains now the two components (tcp and ip). The three variables nodeConfig, tcpConfig and ipConfig contain the configuration (see wns::pyconfig) for these classes.

Let's explore how the Node and those Components work together. The Node has the following interface:

If we take a closer look at the method Node::addComponent(component::Interface*) we can observe that it takes a pointer to a component::Interface as argument. The code detective inside us suggests that TCP and IP must be of type component::Interface. Bingo! So the class hierachy looks something like this:

inline_dotgraph_12.dot

What does the component::Interface look like?

However this is only half the truth, because as we can see from the code snippet above the TCP instancs is assigned to a pointer of type TCPInterface. This means there is not only a component::Interface but also a TCPInterface. TCPInterface must be derived from component::Interface otherwise Node::addComponent can't be called with this type.Further, TCP must be derived from TCPInterface otherwise the assignment to TCPInterface would not be possible. Hence, our hierachy looks now like this:

inline_dotgraph_13.dot

The "Interfaces" (IPInterface, TCPInterface, component::Interface) are abstract (which means they contain only definitions of the methods but no implementation). What is the benefit of these Interfaces? Consider the following: TCP will very likely use an IP instance. But it should not rely on one specific implementation. So it will use the IPInterface instead of IP direct:

inline_dotgraph_14.dot

And we can have more than one IP implementation. As long as it conforms to the IPInterface everything is fine:

inline_dotgraph_15.dot

Still with me? Good! We still have room for optimization! The classes TCP, IPv4 and IPv6 are derived from component::Interface (through TCPInterface and IPInterface). Since the component::Interface is abstract we have to implement all the methods required by component::Interface (see above which methods are required by component::Interface). They are very similar for all three classes (TCP, IPv4, IPv6). To be exact: they are the same. Lucky as we are, we don't need to implement these methods. There is a default implementation available: Component. To get the implementation from Component we derive TCP, IPv4 and IPv6 from Component:

inline_dotgraph_16.dot

Et voila! We've a way to define interfaces for different types of Components and they can be stored in a Node. Now, how does all this look like in C++? We're going to examine only the TCP class. Let's look a the class hierachy again:

inline_dotgraph_17.dot

A simple TCPInterface
Assume the following interface has been defined for an TCP component:

00001 
00002 // Define a new Interface
00003 class TCPInterface :
00004     virtual public service::Service
00005 {
00006 public:
00007     virtual int
00008     getFreePort() = 0;
00009 
00010     virtual std::string
00011     getAddressOfIPInstance() = 0;
00012 
00013     virtual std::string
00014     getName() = 0;
00015 };
Note how we derive from component::Interface here and compare this to the class diagram above. Note further the two new methods that have been defined in the TCPInterface:

These methods are again abstract and need to be implemented.

An TCP implementation
The implementation of TCP might then look like this:

00001 
00002 // Implementation of TCPInterface
00003 class TCP :
00004     virtual public TCPInterface
00005 {
00006 public:
00007     TCP(component::Interface* ci, const pyconfig::View& _pyco) :
00008         pyco(_pyco),
00009         ip(NULL),
00010         componentInterface(ci),
00011         name(_pyco.get<std::string>("name"))
00012     {
00013     }
00014 
00015     // TCPInterface
00016     int getFreePort()
00017     {
00018         // Return always 31337 (only for tests)
00019         return 31337;
00020     }
00021 
00022     // TCPInterface
00023     std::string
00024     getAddressOfIPInstance()
00025     {
00026         return ip->getAddress();
00027     }
00028 
00029     // ComponentInterface
00030     void onNodeCreated()
00031     {
00032         ip = componentInterface->getService<IPInterface*>(pyco.get<std::string>("ipInstance"));
00033     }
00034 
00035     void onWorldCreated()
00036     {
00037         // No inter-node dependecies.
00038     }
00039 
00040     virtual std::string
00041     getName()
00042     {
00043         return name;
00044     }
00045 
00046 private:
00047     wns::pyconfig::View pyco;
00048     // The IP instance below this TCP instance
00049     IPInterface* ip;
00050     component::Interface* componentInterface;
00051     std::string name;
00052 };
Note how we derive from Component additionally here in order to "implement" the component::Interface. The only thing left is the implementation of TCP::getFreePort(), TCP::getAddressOfIPInstance(), TCP::onNodeCreated() and TCP::onWorldCreated from the component::Interface.

Let's see what we can learn from the three methods that have been implemented here:

TCP::getFreePort():
This one is easy. For testing purpose we return an integer. Nothing special.

TCP::getAddressOfIPInstance():
This one is a little bit more difficult. From the name we can guess that we need an instance of something conforming to the IPInterface since we need to ask this instance for its address.

The question is now: How do we find such an instance? We know that the instance must be part of the same Node that the instance of TCP is currently being part of.

At this point the method TCP::onNodeCreated() comes into play. Normally components are not added from outside to a Node but the Node creates all necessary components in its constructor. After all components have been created the method component::Interface::onNodeCreated() of each component is called. Hence, this is the point where a component can try to find other components within its parent Node. You resolve inter Node dependencies only after all Nodes have been constructed and all components have executed their onNodeCreated method. This is the time instance when the onWorldCreated() method is called.

The Node provides special methods to retrieve components from itself.

Retrieve a Component from a Node
A Component can be retrieved from a Node by its name (like a IP instance):

00001 
00002 // retrieve TCP instance from Node
00003 component::tests::TCPInterface* tcp =
00004     node->getService<component::tests::TCPInterface*>("TCP");
Note how the method is informed about the type to be retrieved from the Node. This is necessary since the Node has no idea of the type (it stores component::Interfaces). This is mostly used in component::Interface::onNodeCreated(), i.e. if one component tries to find another component with another type in the same Node.

Typedef Documentation

Definition at line 35 of file Registry.hpp.


Generated on Sun May 27 03:33:01 2012 for openWNS by  doxygen 1.5.5