Tutorial: Building an Rogue Wave Server Application > Designing the Server Object Model > Inverting Relations > Inverting Several Relations in the Same Data Structure
 
Inverting Several Relations in the Same Data Structure
In “Class Line and Its Relations”., you defined a relation where a line uses an input node and an output node. In a use relation, an object can be the target of any number of relations. As shown in the following illustration, a node can be the source and the destination of several Line objects.
Figure 6.2    Input and Output Nodes for the Lines in the Network Object Model
For example, Node 2 is the input node for Line 2 and Line 3, and the output node for Line 1.
List of Pointers
Now you want to be able to know all the lines that use a given node, Node 2 for example.
To do so, you need to store a list of pointers to the origins of the relation in the class Node.
To maintain such a list, Rogue Wave Server provides the class template IlsInvertedRelationList, which you can instantiate to define a list of inverse relations.
In this example, you want to differentiate between input lines and output lines. In other words, you want to maintain two lists of back pointers.
1. To differentiate the input lines from the output lines, add the following line to the class Line in your network.h file.
class Line: public IlsObject
{
public:
   enum {INPUT,OUTPUT};
   Line(NodeP i, NodeP o);
   //...
};
In your network.cpp file, modify the Line constructor, like this:
Line::Line(NodeP i, NodeP o):
   input(*this, i, INPUT),
   output(*this, o, OUTPUT)
{
}
2. In your file network.h, add the following pair of setContext and unsetContext functions to the class Node.
class Node: public IlsObject
{
public:
   ...
   // Line relation inversion
   void setContext(Line&, void*, IlsRelationId);
   void unsetContext(Line&, void*, IlsRelationId);
private:
   IlsInvertedRelationList<Node,Line> inputLines, outputLines;
};
The class template IlsInvertedRelationList allows you to maintain a list of back pointers from Node to Line.
Note: You can declare as many pairs of setContext and unsetContext functions as there are origins for the relation: a node is owned by a domain and used by a line.
3. In your network.cpp file, modify the constructor of the class Node as indicated below:
Node::Node():
   domain(*this),
   inputLines(*this),
   outputLines(*this)
{
}
4. In your file network.cpp, define the setContext and unsetContext functions, like this:
void Node::setContext(Line& l, void*, IlsRelationId id){
   if (id==Line::INPUT) inputLines<<&l;
   else outputLines<<&l;
}
void Node::unsetContext(Line& l, void*, IlsRelationId id){
   if (id==Line::INPUT) inputLines>>&l;
   else outputLines>>&l;
}
5. To test the relation inversion, declare the following two functions in the public part of the class Node in your network.h file.
void printInput();
void printOutput();
6. Add their definitions to your network.cpp file, like this:
void Node::printInput()
{
   cout<<"Input lines"<<endl;
   IlsInvertedRelationList<Node,Line>::Iterator i(inputLines);
   Line* aLine;
   int n = 0;;
   while (i>>aLine) n++;
   cout<<" contains "<<n<<" line(s)"<<endl;
}
void Node::printOutput()
{
   cout<<"Output lines"<<endl;
   IlsInvertedRelationList<Node,Line>::Iterator i(outputLines);
   Line* aLine;
   int n = 0;
   while (i>>aLine) n++;
   cout<<" contains "<<n<<" line(s)"<<endl;
}
7. Add the following lines to your main.cpp file and compile.
#include <network.h>
 
int
main()
{
   NetworkP n=new Network("mynetwork"); // builds a network
   DomainP d=new Domain(); // builds a domain
   n->domains<<d; // insert domain in the network
   NodeP n1=new Node(); // creates n1
   NodeP n2=new Node(); // creates n2
   NodeP n3=new Node(); // creates n3
   NodeP n4=new Node(); // creates n4
   d->nodes<<n1<<n2<<n3<<n4; // inserts nodes in the domain
   LineP l1=new Line(n1,n2); // creates l1
   LineP l2=new Line(n2,n3); // creates l2
   LineP l3=new Line(n2,n4); // creates l3
   d->lines<<l1<<l2<<l3; // inserts lines in the domain
   if (n1->getDomain()) {
      cout<<"n1 is in domain"<<endl;
   }
   d->nodes>>n1;
   if (!n1->getDomain()){
       cout<<"n1 removed from domain"<<endl;
   }
   n2->printInput();
   n2->printOutput();
   return 0;
}
The modified program prints:
n1 is in domain
n1 removed from domain
Input lines
 contains 2 line(s)
Output lines
 contains 1 line(s)
Summary
In this section, you have learned how to automatically maintain back pointers to the origin of an ownership or use relation, using the setContext and unsetContext functions.

Version 5.8
Copyright © 2014, Rogue Wave Software, Inc. All Rights Reserved.