00001 /* Fifth VOS tutorial. Introduction to Metaobjects. 00002 00003 This tutorial file covers: 00004 - Vobject types 00005 - Registering metaobject extenders 00006 - Creating metaobjects 00007 - The meta_cast<> template 00008 - How to use the property metaobject 00009 00010 This file (vostut5server.cc) is released into the public domain. No 00011 restrictions are placed on its use, distribution or inclusion into 00012 other works. 00013 */ 00014 00015 // You must run this program before running vostut5client. 00016 00017 #include <vos/corelibs/vos/vos.hh> 00018 #include <vos/metaobjects/property/property.hh> 00019 00020 void listTypes(Vobject* vob); 00021 00022 int main(int argc, char** argv) 00023 { 00024 cout << "VOS Tutorial 5 Server\n\n"; 00025 00026 LocalSocketSite localsite(&NoAccessControl::static_); 00027 localsite.setTimeoutOnSelect(-1); 00028 00029 /* When you create a data structure out of several Vobjects as we 00030 did in the previous tutorial, the various objects will take on 00031 different tasks. The "sphere" object acts as a container for 00032 the other objects, the "position" stores the position value, 00033 the "radius" stores the radius and so forth. It is not 00034 sufficient to differentiate vobjects by their parent-child 00035 relationships, however. It may obvious be that the object 00036 named "sphere" describes a sphere, but what if we want to name 00037 it "ball" or "planet"? 00038 00039 A Vobject may have a list of "types" associated with it. A 00040 type is simply an agreed-upon string which indicates to the 00041 application that this Vobject adheres to a certain interface. 00042 This interface may be that the Vobject has certain children 00043 with specific meanings (a child named "position" describes its 00044 position, for example) or it may indicate that the Vobject 00045 accepts and generates certain types of messages. A Vobject can 00046 have several type strings, indicating that it adheres to 00047 multiple standands simultaneously (it is up to the user to 00048 avoid conflicts). 00049 00050 When creating an object, we list the types it supports. This 00051 is variable-argument method (eg it uses "...") so you must 00052 always have a 0 to indicate the end of the list. 00053 */ 00054 vRef<Vobject> planet = localsite.createMetaObject("planet", "tutorial:sphere", 0); 00055 00056 listTypes(&planet); 00057 00058 00059 // We can add types: 00060 planet->addType("tutorial:class M"); 00061 listTypes(&planet); 00062 00063 00064 // You can check to see if a type is present on a Vobject using 00065 // the count() method. Technically this returns the number of 00066 // time the type shows up in the set, but because it is a set of 00067 // unique elements this will always be either 1 or 0. 00068 00069 if(planet->getTypes().count("tutorial:class M")) { 00070 cout << "vostut5server: It it a habitable planet.\n"; 00071 } 00072 00073 /* If it occured to you that the type of a Vobject could be 00074 similar to class of a C++ object, you're right on track. VOS 00075 allows you to automatically map a Vobject type to a C++ class. 00076 The class then implements a C++ method interface for the 00077 operations on that Vobject. Using the MetaObject class called 00078 you can dynamically extend the capabilities of a given Vobject. 00079 This tutorial demonstrates how to create a vobject which 00080 implements functionality from the "Property" extension. 00081 */ 00082 00083 // First we must register the Property extension with VOS. This 00084 // should only ever be done once, in the initialization of your 00085 // program. 00086 Property::registerExtenders(); 00087 00088 00089 /* typeid() is a part of the C++ language which provides some 00090 information about C++ classes. The name() method gives us a 00091 unique name which refers specifically to that class. By 00092 calling Property::registerExtenders(), we have associated the 00093 C++ Property class with a certain Vobject type and type 00094 extension. The createMetaObject method adds that extension to 00095 the newly created MetaObject. 00096 00097 Here's another way of looking at it: we would like the new 00098 Vobject we are creating to have the C++ interface defined by 00099 the "Property" class, we ask createMetaObject to extend the 00100 Vobject appropriately to support this. 00101 */ 00102 vRef<MetaObject> position = localsite.createMetaObject("position", typeid(Property).name(), 0); 00103 00104 listTypes(&position); 00105 00106 planet->insertChild(-1, "position", &position); 00107 00108 00109 /* To extract the Property class interface from the position 00110 vobject, we use the template method MetaObject::meta_cast<>. 00111 Given a Vobject or MetaObject, meta_cast<> returns the desired 00112 c++ interface to that vobject if available, or NULL if not. 00113 Think of it as an elaborate typecast. 00114 */ 00115 Property* positionproperty = MetaObject::meta_cast<Property*>(&position); 00116 00117 /* The "positionproperty" object allows us to access methods 00118 specific to the property extension. We can access the usual 00119 Vobject API (insertChild, getTypes, etc) through 00120 "positionproperty" well. */ 00121 00122 /* Perhaps you have been wondering what the Property extension 00123 actually does! This extension defines a standard way for 00124 storing and accessing a block of data in a Vobject. It is very 00125 much like a file, with read() and write() methods. The 00126 property metaobject is used by nearly everything else as a 00127 common way of storing data in a Vobject. 00128 */ 00129 00130 // To set a property's value, use replace(). The first parameter 00131 // is the new contents of the property, the second parameter is 00132 // the datatype of the property's value (such as a MIME type). 00133 00134 positionproperty->replace("1 2 3", "text/x-vector-float"); 00135 00136 00137 // To read a property value, use read() 00138 00139 cout << "vostut5server: The property value of " << positionproperty->getURL().getString() 00140 << " is " << positionproperty->read() << endl; 00141 00142 00143 // You can selectively change a part of a property using write(). 00144 // The first argument is the offset, the second is the new section. 00145 00146 positionproperty->write(2, "4"); 00147 00148 cout << "vostut5server: The property value of " << positionproperty->getURL().getString() 00149 << " is now " << positionproperty->read() << endl; 00150 00151 00152 /* "LocalProperty" is a subclass of "Property" which implements 00153 the property type as a local vobject, answering queries from 00154 remote vobjects. Because "Property" is an abstract class which 00155 can represent both local and remote properties, we must 00156 meta_cast to LocalProperty to set the access control. 00157 */ 00158 LocalProperty* localproperty = MetaObject::meta_cast<LocalProperty*>(&position); 00159 00160 /* We must set an access control policy for remote users. This 00161 policy is used to control what actions are permitted on this 00162 object. There can actually be a "chain" of access control 00163 policies; the first parameter indicates that the new policy 00164 should be added to the end of the chain. We are using a 00165 read-only policy, so remote users will be able to read but not 00166 change the value of this property. 00167 */ 00168 localproperty->insertPropertyAccessControl(-1, &ReadOnlyPropertyAccessControl::static_); 00169 00170 00171 cout << "Going into runloop now.\n"; 00172 00173 while(true) { 00174 localsite.flushIncomingBuffers(); 00175 } 00176 } 00177 00178 void listTypes(Vobject* vob) 00179 { 00180 // The type set is returned as an STL set<string>. Simply use 00181 // standard iterators to iterate over the set. 00182 00183 const Vobject::TypeSet& types = vob->getTypes(); 00184 00185 cout << "Types for " << vob->getURL().getString() << ": "; 00186 for(Vobject::TypeSet::const_iterator i = types.begin(); i != types.end(); i++) 00187 { 00188 if(i != types.begin()) cout << ", "; 00189 cout << (*i); 00190 } 00191 cout << "\n"; 00192 } 00193