00001 /* Fourth VOS tutorial. Linking Vobjects together. 00002 00003 This tutorial covers: 00004 - Inserting, replacing and removing Vobjects as children of other 00005 Vobjects 00006 - Linking local and remote Vobjects 00007 - Finding specific a child by name 00008 - Vobject paths 00009 - Listing a Vobject's children 00010 - Listing a Vobject's parents 00011 00012 This file (vostut4.cc) is released into the public domain. No 00013 restrictions are placed on its use, distribution or inclusion into 00014 other works. 00015 */ 00016 00017 #include <vos/corelibs/vos/vos.hh> 00018 00019 void listChildren(Vobject* vobject); 00020 void listParents(Vobject* vobject); 00021 00022 // The server from tutorial 3 ("vostut3server") should be run before 00023 // running this tutorial. 00024 00025 int main(int argc, char** argv) 00026 { 00027 cout << "VOS Tutorial 4\n\n"; 00028 00029 LocalSocketSite localsite(&NoAccessControl::static_); 00030 localsite.setTimeoutOnSelect(-1); 00031 00032 /* We saw in the previous tutorial how one Vobject can access 00033 another. We now look at how Vobjects may be linked together to 00034 create network-accessable data structures. In this tutorial, 00035 we demonstrate how one might build a data structure describing 00036 a sphere with VOS. 00037 00038 A Vobject may consist of a number of incoming "parent" links 00039 and outgoing "child" links. The terms parent and child come 00040 from common computer science usage for describing hierarchical 00041 structures. At the top level is the local site, which is a 00042 parent to all Vobjects it hosts (and therefore has each Vobject 00043 as a child). When a Vobject is created, it is automatically 00044 made a child of its site. 00045 */ 00046 00047 // Create some objects to play with. 00048 vRef<Vobject> sphere = localsite.createMetaObject("sphere", 0); 00049 vRef<Vobject> tertius = localsite.createMetaObject("tertius", 0); 00050 vRef<Vobject> quartus = localsite.createMetaObject("quartus", 0); 00051 vRef<Vobject> quintus = localsite.createMetaObject("quintus", 0); 00052 vRef<Vobject> sextus = localsite.createMetaObject("sextus", 0); 00053 vRef<Vobject> septimus = localsite.createMetaObject("septimus", 0); 00054 00055 listChildren(&localsite); 00056 cout << "\n"; 00057 00058 /* Each Vobject stores a list other Vobjects it links to. This is 00059 called the child list. It is an ordered, associative list, 00060 where each position in the list consists of a string called the 00061 "contextual name" and a link to the Vobject it points to. 00062 00063 Initially, the Vobject "sphere" does not have any children. 00064 The insertChild() method is used to add children. The first 00065 parameter tells where in the list to insert the child, with the 00066 value "-1" used to append to the end of the child list. The 00067 link is named "position", so in our example the the linked-to 00068 child vobject (tertius) describes the position of its parent 00069 (the sphere). 00070 */ 00071 cout << "Appending tertius as \"position\"\n"; 00072 sphere->insertChild(-1, "position", &tertius); 00073 00074 /* For the moment, don't worry about how the value of position 00075 will be stored in the tertius Vobject. This is discussed in a 00076 later tutorial. For this tutorial we are concentrating on the 00077 abstract structure. 00078 */ 00079 00080 /* Print out the children of the sphere and the parents of 00081 tertius. Since tertius has been added as a child to sphere, 00082 sphere is now listed as a parent of tertius. 00083 */ 00084 listChildren(&sphere); 00085 listParents(&tertius); 00086 cout << "\n"; 00087 00088 00089 /* Now we add a few more vobjects to the sphere. As demonstrated 00090 here, the child list can have more than one link to the same 00091 Vobject and you can have multiple entries with the same 00092 contextual name. 00093 */ 00094 cout << "Appending quartus as \"orientation\"\n"; 00095 sphere->insertChild(-1, "orientation", &quartus); 00096 00097 cout << "Appending quintus as \"radius\"\n"; 00098 sphere->insertChild(-1, "radius", &quintus); 00099 00100 cout << "Appending quartus as \"position\"\n"; 00101 sphere->insertChild(-1, "position", &quartus); 00102 00103 listChildren(&sphere); 00104 listParents(&quartus); 00105 cout << "\n"; 00106 00107 00108 /* Of course we can insert a new item anywhere. We'll add the 00109 Vobject "sextus" describing the color of our sphere so that it 00110 occupies position 2. This shifts the rest of the list (from 00111 position 2 to the end) up one position to make room for the 00112 newly inserted child. Note: position 0 inserts a child at the 00113 beginning of the list. 00114 */ 00115 cout << "Inserting sextus as \"color\" into position 2\n"; 00116 sphere->insertChild(2, "color", &sextus); 00117 00118 listChildren(&sphere); 00119 cout << "\n"; 00120 00121 00122 /* Oops! We have two children named "position"! The sphere can't 00123 very well be in two places at once, can it? The setChild() 00124 method allows us to replace a child at one position with 00125 another, which is much more efficient than removing the old 00126 vobject and inserting the new one. Here we replace the second 00127 "position" child (at list position 4 now) with a 00128 different object that will store our sphere's mass. 00129 */ 00130 cout << "Replacing quartus in position 4 with septimus as \"mass\"\n"; 00131 sphere->setChild(4, "mass", &septimus); 00132 00133 listChildren(&sphere); 00134 cout << "\n"; 00135 00136 /* It's also sort of silly for a sphere to have an orientation, 00137 seeing as how it is perfectly round. Let's remove the child 00138 storing the orientation. The removeChild() method removes the 00139 list item at the given position and move everything above it 00140 down a notch to fill in the gap. 00141 */ 00142 cout << "Removing quintus (\"orientation\") from position 1\n"; 00143 sphere->removeChild(1); 00144 00145 listChildren(&sphere); 00146 cout << "\n"; 00147 00148 00149 /* Some detail specifying a position in a child list: positive 00150 positions are counted from the beginning and negative 00151 positions are counted from the end. The start of the list is 00152 always 0 and the end of the list is always -1. This means 00153 that positions of -2 (second-to-last position), -3, -10 and so 00154 on are perfectly legal (provided the list is at least of that 00155 length). 00156 */ 00157 cout << "Removing septimus (\"mass\") from the last position\n"; 00158 sphere->removeChild(-1); 00159 00160 listChildren(&sphere); 00161 cout << "\n"; 00162 00163 try { 00164 /* What makes parent-child linking of Vobjects really 00165 interesting is the fact that you can freely mix local and 00166 remote Vobjects. Here we acquire a remote object running 00167 on a different site and manipulate it exactly the same way 00168 as if it were local. 00169 */ 00170 vRef<Vobject> primus = Vobject::findObjectFromRoot("vop://localhost:4231/primus"); 00171 00172 cout << "Adding local vobject septimus to remote to remote vobject primus\n"; 00173 primus->insertChild(-1, "septimus", &septimus); 00174 00175 listChildren(&primus); 00176 listParents(&septimus); 00177 cout << "\n"; 00178 00179 00180 cout << "Adding remote vobject primus to local vobject quartus\n"; 00181 quartus->insertChild(-1, "primus", &primus); 00182 00183 listChildren(&quartus); 00184 listParents(&primus); 00185 cout << "\n"; 00186 } catch(runtime_error& e) { 00187 cerr << "An exception occured: " << e.what() << "\n"; 00188 } 00189 00190 /* Once we have created a VOS data structure, we want to be able 00191 to access it. One way is by iterating over the entire contents 00192 of the child list (which is demonstrated in the listChildren() 00193 function below). The other is to use the findChild() and 00194 findObject() methods. 00195 00196 The findChild() method returns the Vobject::ParentChildRelation 00197 structure describing the link with the given contextual name. 00198 If more than one link has the same contextual name, then the 00199 link with position closest to the beginning is returned. This 00200 simply consists of four fields, the parent, the child, and the 00201 position and contextual name in the parent's child list. 00202 */ 00203 vRef<Vobject::ParentChildRelation> pcr = sphere->findChild("color"); 00204 cout << "Results of findChild():\n"; 00205 cout << " Parent: " << pcr->parent->getURL().getString() << "\n"; 00206 cout << " Position: " << pcr->position << "\n"; 00207 cout << " Contextual name: " << pcr->contextual_name << "\n"; 00208 cout << " Child: " << pcr->child->getURL().getString() << "\n"; 00209 00210 /* The findObject() method returns just the Vobject itself, but 00211 can take a path going through several Vobjects. A Vobject path 00212 is a slash-separated list of contextual names to follow to find 00213 the Vobject. It is intended to resemble a familiar file system 00214 path and works essentially the same way, although the notation 00215 ".." is not available. While directories in a filesystem only 00216 have one parent directory, Vobjects usually have two or more 00217 parent Vobjects! 00218 */ 00219 vRef<Vobject> color = localsite.findObject("sphere/color"); 00220 00221 listParents(&color); 00222 00223 /* One final method for accessing parent-child relationships: 00224 findParent() returns the parent-child relationship structure 00225 associated with a specific parent of this Vobject. 00226 */ 00227 vRef<Vobject::ParentChildRelation> pcr2 = color->findParent(*sphere); 00228 cout << "Results of findParent():\n"; 00229 cout << " Parent: " << pcr2->parent->getURL().getString() << "\n"; 00230 cout << " Position: " << pcr2->position << "\n"; 00231 cout << " Contextual name: " << pcr2->contextual_name << "\n"; 00232 cout << " Child: " << pcr2->child->getURL().getString() << "\n"; 00233 00234 00235 cout << "Going into runloop now. Try connecting to " << localsite.getURL().getString() << " using \"mesh\"\n"; 00236 cout << "to inspect the current vobject structure.\n"; 00237 00238 while(true) { 00239 localsite.flushIncomingBuffers(); 00240 } 00241 } 00242 00243 void listChildren(Vobject* vobject) 00244 { 00245 // getChildren() returns the child list for this Vobject. This is 00246 // a list of Vobject::ParentChildRelation structures. It is 00247 // intended for read only access and you should never ever modify 00248 // the contents of this list directly. 00249 const Vobject::ChildList& childlist = vobject->getChildren(); 00250 00251 cout << "Children of " << vobject->getURL().getString() << ":\n"; 00252 00253 // You can efficiently iterate over the list with an int: 00254 for(int i = 0; i < childlist.size(); i++) { 00255 Vobject::ParentChildRelation* pcr = childlist[i]; 00256 cout << " #" << pcr->position << " " << pcr->contextual_name << " -> " 00257 << pcr->child->getURL().getString() << "\n"; 00258 } 00259 } 00260 00261 void listParents(Vobject* vobject) 00262 { 00263 // getParents returns an STL set storing the 00264 // Vobject::ParentChildRelation structures describing each link to 00265 // this Vobject in some Vobject's child list. As with the child 00266 // list, this is for read only access and you should never modify 00267 // this set directly. 00268 const Vobject::ParentSet& parentset = vobject->getParents(); 00269 00270 cout << "Parents of " << vobject->getURL().getString() << ":\n"; 00271 00272 // Use an STL const_iterator to iterate over this set. 00273 for(Vobject::ParentSet::const_iterator i = parentset.begin(); i != parentset.end(); i++) { 00274 Vobject::ParentChildRelation* pcr = *i; 00275 cout << " " << pcr->parent->getURL().getString() << " linked as #" 00276 << pcr->position << " " << pcr->contextual_name << "\n"; 00277 } 00278 }