interreality.org [VOS]
[Home] [About]
[Screenshots]
[Download]
[News]
[Community]
[Documentation] [Manual]
[Bugs & Requests] [Wiki]

/home/tetron/hack/vos/apps/tutorials/vostut7hello.cc

Go to the documentation of this file.
00001 /* Seventh VOS tutorial.  Creating your own MetaObjects
00002 
00003    This tutorial covers:
00004 
00005    This file (vostut7hello.cc) is released into the public domain.  No
00006    restrictions are placed on its use, distribution or inclusion into
00007    other works.
00008 */
00009 
00010 #include "vostut7hello.hh"
00011 
00012 using namespace VUtil;
00013 using namespace VOS;
00014 
00015 // The hello constructor.  Nice and simple :-)
00016 
00017 Hello::Hello(VobjectBase* superobject)
00018     : MetaObject(superobject)
00019 {
00020 }
00021 
00022 // Return the VOS type
00023 
00024 const std::string Hello::getVOSType()
00025 {
00026     return "tutorial:hello";
00027 }
00028 
00029 // That's it for the "Hello" base class!
00030 
00031 
00032 // Now for RemoteHello.
00033 
00034 // The constructor for LocalHello.
00035 
00036 RemoteHello::RemoteHello(VobjectBase* superobject)
00037     : Hello(superobject)
00038 { }
00039 
00040 
00041 // The client stub implementation of hello.
00042 
00043 std::string RemoteHello::hello(const std::string& s)
00044 {
00045     // will hold return value
00046     std::string ret;
00047 
00048     /* We can supply some parameters to the message constructor to
00049        initialize some of the fields on the message, including
00050        generating a nonce.  A "nonce" is a unique identifier
00051        associated with this message that will be used to match the
00052        reply message (which will bear the same nonce).
00053     */
00054     vRef<Message> m(new Message(this, "tutorial:hello", true), false);
00055 
00056     m->appendField("word", s);
00057 
00058     /* Send it off.  Note: since 'this' is a remote object, by sending
00059        a message to 'this' we are actualy causing the message to be
00060        delivered to the actual vobject over the network.
00061     */
00062     vRef<Message> n = ProcessMessage::sendMsgAndWaitForReply(this, m);
00063 
00064     try {
00065 
00066         // We got a reply back.  Extract the answer from the "text" field.
00067         ret = n->getField("word")->value;
00068 
00069     } catch(NoSuchFieldError) {
00070 
00071         // Whoops.  There wasn't a "word" field.
00072         // We could perhaps throw an exception here.
00073 
00074         ret = "***site did not return a word field***";
00075     }
00076 
00077     // return our results.
00078     return ret;
00079 }
00080 
00081 
00082 // Constructs a RemoteHello object and returns it.  This is necessary
00083 // since you can't take the address of a constructor and call it like
00084 // a normal function or method pointer.
00085 
00086 MetaObject* RemoteHello::new_RemoteHello(VobjectBase* superobject, const std::string& type)
00087 {
00088     return new RemoteHello(superobject);
00089 }
00090 
00091 
00092 // All done with RemoteHello!
00093 
00094 
00095 // Now the constructor for LocalHello.
00096 
00097 LocalHello::LocalHello(VobjectBase* superobject)
00098     : Hello(superobject)
00099 {
00100     // only do this once
00101     static bool init = true;
00102     if(init) {
00103         init = false;
00104 
00105         /* Here we add a method to be called when this Vobject receives a
00106            message with specific method field.  The addMessageHandler
00107            method associates the message method ("tutorial:hello") with a
00108            C++ method to call (&LocalHello::handleHello) and a particular
00109            object to call in on (this).
00110         */
00111         VobjectBase::addMessageHandler("tutorial:hello", &LocalHello::handleHello);
00112     }
00113 }
00114 
00115 
00116 // The actual hello method.  Yes, all the trouble just to access this
00117 // method over a network :-)
00118 
00119 std::string LocalHello::hello(const std::string& s)
00120 {
00121     return ("Hello there!  You said \"" + s + "\"");
00122 }
00123 
00124 
00125 
00126 // This is the handler method registered with addMessageHandler() and
00127 // called by VOS when a message bearing the method "tutorial:hello" is
00128 // received by this object.
00129 
00130 void LocalHello::handleHello(Message* m)
00131 {
00132     // Somebody has said hello to us.  We will act upon the message
00133     // and send a reply.
00134 
00135     vRef<Message> reply(new Message(this, m, "tutorial:hello-reply"), false);
00136 
00137     try {
00138         // Now call hello() with the field called "word".
00139 
00140         std::string s = hello(m->getField("word")->value);
00141 
00142 
00143         // The result goes into a field called "word" in the reply.
00144 
00145         reply->appendField("word", s);
00146 
00147     } catch(NoSuchFieldError) {
00148 
00149         // oops!  The message we got didn't have the field we were looking for.
00150         reply->appendField("error", "need a field \"word\"");
00151 
00152     }
00153 
00154     try {
00155         // Get a handle on the object that sent this message to us
00156         // and send it the reply.
00157 
00158         vRef<Vobject> v = findObject(m->getFrom());
00159 
00160         v->sendMessage(reply);
00161 
00162     } catch(NoSuchSiteError) {
00163     } catch(NoSuchObjectError) {
00164     } catch(AccessControlError) {
00165     } catch(RemoteError) {
00166     } catch(BadURLError) {
00167     }
00168 }
00169 
00170 
00171 // Constructs a LocalHello object and returns it.  This is necessary
00172 // since you can't take the address of a constructor and call it like
00173 // a normal function or method pointer.
00174 
00175 MetaObject* LocalHello::new_LocalHello(VobjectBase* superobject, const std::string& type)
00176 {
00177     return new LocalHello(superobject);
00178 }
00179 
00180 
00181 /* The following code between BEGIN_ and END_ will be executed
00182    _before_ the program main().  We want to register our MetaObject extension
00183    with Site, so we add our new_LocalHello and new_RemoteHello factory
00184    methods to a global table of MetaObject types and their factories.
00185 */
00186 BEGIN_REGISTER_METAOBJECT_FACTORIES(Hello)
00187 
00188 /* Registering an extension consists of supplying a type string
00189    and a function to call to construct a new metaobject for that
00190    type.  Here we associate the new_LocalHello function for the
00191    abstract class, the local class, and the VOS type name, meaning
00192    the user can call Site::createVobject() with any of
00193    these three strings and get an object with the LocalHello extension.
00194 */
00195 Site::addLocalMetaObjectFactory(typeid(Hello).name(), &LocalHello::new_LocalHello);
00196 Site::addLocalMetaObjectFactory(typeid(LocalHello).name(), &LocalHello::new_LocalHello);
00197 Site::addLocalMetaObjectFactory("tutorial:hello", &LocalHello::new_LocalHello);
00198 
00199 /* Note that for remote objects the VOS type name is extremely
00200    important: it is the VOS type name we get from the network, and
00201    we use it to automatically instantiate the correct extensions
00202    for the newly discovered object.
00203 */
00204 Site::addRemoteMetaObjectFactory(typeid(Hello).name(), "tutorial:hello", &RemoteHello::new_RemoteHello);
00205 Site::addRemoteMetaObjectFactory(typeid(RemoteHello).name(), "tutorial:hello", &RemoteHello::new_RemoteHello);
00206 Site::addRemoteMetaObjectFactory("tutorial:hello", "tutorial:hello", &RemoteHello::new_RemoteHello);
00207 END_REGISTER_METAOBJECT_FACTORIES(Hello)
00208