Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/metaobjects/property/property.cc

Go to the documentation of this file.
00001 /*
00002     This file is part of the Virtual Object System of
00003     the Interreality project (http://interreality.org).
00004 
00005     Copyright (C) 2001, 2002 Peter Amstutz
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00020 
00021     Peter Amstutz <tetron@interreality.org>
00022 */
00023 #include <stdio.h>
00024 #include <iostream>
00025 #include <fstream>
00026 #include <stdexcept>
00027 #include <string>
00028 #include <vector>
00029 
00030 
00031 #include <vos/corelibs/vos/vos.hh>
00032 #include "property.hh"
00033 #include <typechain/typechain.hh>
00034 
00035 #include <assert.h>
00036 
00037 
00038 using namespace std;
00039 
00040 NoPropertyAccessControl NoPropertyAccessControl::static_;
00041 ReadOnlyPropertyAccessControl ReadOnlyPropertyAccessControl::static_;
00042 DoNothingPropertyListener DoNothingPropertyListener::static_;
00043 DoNothingPropertySecurityInitializer DoNothingPropertySecurityInitializer::static_;
00044 PropertySecurityInitializer* LocalProperty::securitycallback =
00045     &DoNothingPropertySecurityInitializer::static_;
00046 
00047 map<string, PropertyAccessControl::AssignAC> PropertyAccessControl::policies;
00048 
00049 void PropertyAccessControl::addPolicy(PropertyAccessControl* ac)
00050 {
00051     policies[ac->getPolicyName()].ac = ac;
00052     policies[ac->getPolicyName()].fac = 0;
00053 }
00054 
00055 void PropertyAccessControl::addPolicyFactory(const string& name, PropertyAccessControlFactory ac)
00056 {
00057     policies[name].ac = 0;
00058     policies[name].fac = ac;
00059 }
00060 
00061 PropertyAccessControl* PropertyAccessControl::getPolicy(const string& name, LocalProperty* lv)
00062 {
00063     if(policies.count(name)) {
00064         if(policies[name].ac) return policies[name].ac;
00065         else {
00066             return (*policies[name].fac)(name, lv);
00067         }
00068     } else return 0;
00069 }
00070 
00071 void PropertyAccessControl::removePolicy(const string& name)
00072 {
00073     policies.erase(name);
00074 }
00075 
00076 
00077 /* Constructors */
00078 
00079 
00080 
00081 Property::Property(MetaObject* superobject)
00082     : MetaObject(superobject), raw_data(""), raw_datatype("?"), raw_length(-1), data(""), datatype("?"), data_length(0), decoded(false)
00083 {
00084 }
00085 
00086 
00087 
00088 /* Property base class */
00089 
00090 const string Property::getType()
00091 {
00092     return string("property:property");
00093 }
00094 
00095 void Property::checkDecoded() {
00096     if(!decoded) {
00097         LOG("Property", 4, "Property::checkDecoded: Decoding data of type " << raw_datatype << "." );
00098         readRaw(data);  // XXX note: this may perform a network-read unecesarily!
00099         datatype = TypeChain::decode(data, raw_datatype);
00100         data_length = data.size();
00101         decoded = true;
00102     }
00103 }
00104 
00105 
00106 int Property::getLength() {
00107     checkDecoded();
00108     return data_length;
00109 }
00110 
00111 void Property::read(string& target) {
00112     read(target, 0, -1);
00113 }
00114 
00115 void Property::read(string& target, int start, int length) {
00116     checkDecoded();
00117     if(length == -1)
00118         target = data.substr(start);
00119     else
00120         target = data.substr(start, length);
00121 }
00122 
00123 string Property::read() {
00124     string s;
00125     read(s);
00126     return s;
00127 }
00128 
00129 string Property::read(int start, int length) {
00130     string s;
00131     read(s, start, length);
00132     return s;
00133 }
00134 
00135 int Property::getRawLength() {
00136     return raw_length;
00137 }
00138 
00139 void Property::readRaw(string& target)  {
00140     readRaw(target, 0, getRawLength());
00141 }
00142 
00143 void Property::readRaw(string& target, int start, int length)  {
00144     if(length == -1)
00145         target = raw_data.substr(start);
00146     else
00147         target = raw_data.substr(start, length);
00148 }
00149 
00150 string Property::readRaw() {
00151     string s;
00152     readRaw(s);
00153     return s;
00154 }
00155 
00156 string Property::readRaw(int start, int length) {
00157     string s;
00158     readRaw(s, start, length);
00159     return s;
00160 }
00161 
00162 void Property::asyncRead()
00163 {
00164     string dcp;
00165     read(dcp);
00166     vRef<PropertyEvent> event = new PropertyEvent(PropertyEvent::PropertyReplace,
00167                                                   *this, *this,
00168                                                   dcp, getDataType(),
00169                                                   false);
00170     for(PropertyListenerMap::iterator i = propertyListeners.begin(); i != propertyListeners.end(); i++) {
00171         (*i).second->notifyPropertyChange(*event);
00172     }
00173 }
00174 
00175 void Property::asyncRead(int start, int length)
00176 {
00177     string dcp;
00178     read(dcp, start, length);
00179     vRef<PropertyEvent> event = new PropertyEvent(PropertyEvent::PropertyWrite,
00180                                                   *this, *this,
00181                                                   start, length,
00182                                                   dcp, getDataType(),
00183                                                   false);
00184     for(PropertyListenerMap::iterator i = propertyListeners.begin(); i != propertyListeners.end(); i++) {
00185         (*i).second->notifyPropertyChange(*event);
00186     }
00187 }
00188 
00189 
00190 void Property::write(int start, const string& newdata) {
00191     if(start < 0)
00192         start = raw_data.size() + start;
00193     raw_data.replace(start, newdata.size(), newdata);
00194     raw_length = raw_data.size();
00195     decoded = false;
00196 }
00197 
00198 
00199 void Property::replace(const string& newdata, const string& newtype) {
00200     raw_data = newdata;
00201     // if no type identifier was supplied, we assume that it should be the same as the old one.
00202     if(newtype != "?")
00203         raw_datatype = newtype;
00204     raw_length = raw_data.size();
00205     decoded = false;
00206 }
00207 
00208 const string Property::getDataType() {
00209     checkDecoded();
00210     return datatype;
00211 }
00212 
00213 
00214 const string Property::getRawDataType() {
00215     return raw_datatype;
00216 }
00217 
00218 void Property::registerExtenders()
00219 {
00220     static bool done = false;
00221     if(! done) {
00222     LocalSite::addLocalObjectExtension(typeid(LocalProperty).name(),
00223                                          &LocalProperty::new_LocalProperty);
00224     LocalSite::addLocalObjectExtension(typeid(Property).name(),
00225                                          &LocalProperty::new_LocalProperty);
00226     LocalSite::addLocalObjectExtension("property:property",
00227                                          &LocalProperty::new_LocalProperty);
00228 
00229     RemoteSite::addRemoteObjectExtension(typeid(RemoteProperty).name(),
00230                                           &RemoteProperty::new_RemoteProperty);
00231     RemoteSite::addRemoteObjectExtension(typeid(Property).name(),
00232                                           &RemoteProperty::new_RemoteProperty);
00233     RemoteSite::addRemoteObjectExtension("property:property",
00234                                           &RemoteProperty::new_RemoteProperty);
00235     done = true;
00236     }
00237 }
00238 
00239 void Property::setProperty(Vobject& on,
00240                            const string& propname,
00241                            const string& propval,
00242                            const string& valtype,
00243                            PropertyAccessControl* pac)
00244     throw (AccessControlError, TypeChain::DecodeError, RemoteError)
00245 {
00246     rREF(Vobject::ParentChildRelation&, r, setPropertyWithReturn(on, propname, propval, valtype, pac), );
00247 }
00248 
00249 Vobject::ParentChildRelation& Property::setPropertyWithReturn(Vobject& on,
00250                                                               const string& propname,
00251                                                               const string& propval,
00252                                                               const string& valtype,
00253                                                               PropertyAccessControl* pac,
00254                                                               bool letErrorThrough)
00255     throw (AccessControlError, TypeChain::DecodeError, RemoteError)
00256 {
00257     int i;
00258     for(i = propname.size()-1; i >= 0  && propname[i] != '/'; i--);
00259     string path = (i > 0 ? propname.substr(0, i) : "");
00260     string name = propname.substr(i+1);
00261     try {
00262         vRef<Vobject> parent = on.findObject(path);
00263         vRef<ParentChildRelation> c = parent->findChild(name);
00264         if(Property* p = meta_cast<Property*>(c->child)) {
00265             p->replace(propval, valtype);
00266         }
00267         c->acquire();
00268         return *c; // released by: the caller of this method
00269     } catch(Vobject::NoSuchObjectError x) {
00270         if(letErrorThrough) throw x;
00271         vRef<Vobject> parent = on.findObject(path);
00272         //pREF(MetaObject*, m, Site::getDefaultPeer()->createMetaObject(propname.c_str(), typeid(Property).name(), 0),
00273         vRef<LocalSite> ls = Site::getDefaultPeer();
00274         vRef<MetaObject> m = ls->createMetaObject(propname.c_str(),
00275                                                   "property:property", 0);
00276         LocalProperty* lp = MetaObject::meta_cast<LocalProperty*>(&m);
00277         if(pac)
00278             lp->insertPropertyAccessControl(-1, pac);
00279         lp->addParentListener(&DoNothingListener::static_);
00280         parent->insertChild(-1, name, lp);
00281         return setPropertyWithReturn(on, propname, propval, valtype, pac, true);
00282     }
00283 }
00284 
00285 void Property::setProperty(Vobject& on,
00286                            const string& propname,
00287                            double propval,
00288                            PropertyAccessControl* pac)
00289     throw (AccessControlError, TypeChain::DecodeError, RemoteError)
00290 {
00291     rREF(Vobject::ParentChildRelation&, r, setPropertyWithReturn(on, propname, propval, pac), );
00292 }
00293 
00294 Vobject::ParentChildRelation& Property::setPropertyWithReturn(Vobject& on,
00295                                                               const string& propname,
00296                                                               double propval,
00297                                                               PropertyAccessControl* pac)
00298     throw (AccessControlError, TypeChain::DecodeError, RemoteError)
00299 {
00300 
00301 
00302     try {
00303         Vobject::ParentChildRelation& c = on.findChild(propname);
00304         if(Property* p = meta_cast<Property*>(c.child)) {
00305             char num[32];
00306             snprintf(num, sizeof(num), "%f", propval);
00307             p->replace(num, "text/x-float");
00308         }
00309         return c; // released by: the caller of this method
00310     } catch(Vobject::NoSuchObjectError) {
00311         vRef<MetaObject> m = Site::getDefaultPeer()->createMetaObject( propname.c_str(), typeid(Property).name(), 0);
00312         LocalProperty* lp = MetaObject::meta_cast<LocalProperty*>(&m);
00313         if(pac)
00314             lp->insertPropertyAccessControl(-1, pac);
00315         lp->addParentListener(&DoNothingListener::static_);
00316         on.insertChild(-1, propname, lp);
00317         return setPropertyWithReturn(on, propname, propval, pac);
00318     }
00319 }
00320 
00321 string Property::getProperty(Vobject& on, const string& name) {
00322     vRef<Vobject> v = on.findObject(name);
00323     Property* p = meta_cast<Property*>(&v);
00324     if(!p) throw bad_cast();
00325     return p->read();
00326 }
00327 
00328 string Property::getProperty(Vobject& on, const string& name, const string& defVal) {
00329     try {
00330         return Property::getProperty(on, name);
00331     } catch(Vobject::NoSuchObjectError) {
00332         return defVal;
00333     } catch(bad_cast) {
00334         return defVal;
00335     }
00336 }
00337 
00338 
00339 int Property::getIntProperty(Vobject& on, const string& name) {
00340     int v;
00341     string s;
00342     vRef<Property> p = meta_cast<Property*>(&(on.findObject(name)));
00343     if(!&p)
00344         throw bad_cast();
00345     p->read(s);
00346     sscanf(s.c_str(), "%d", &v);
00347     return v;
00348 }
00349 
00350 int Property::getIntProperty(Vobject& on, const string& name, int defaultVal) {
00351     try {
00352         return Property::getIntProperty(on, name);
00353     } catch(NoSuchObjectError) {
00354         return defaultVal;
00355     } catch(bad_cast) {
00356         return defaultVal;
00357     }
00358 }
00359 
00360 int Property::getIntProperty(Vobject& on, const string& name, int lowerLimit,
00361     int upperLimit)
00362 {
00363     int v;
00364     v = Property::getIntProperty(on, name);
00365     if(v < lowerLimit) return lowerLimit;
00366     if(v > upperLimit) return upperLimit;
00367     return v;
00368 }
00369 
00370 int Property::getIntProperty(Vobject& on, const string& name, int defaultVal,
00371     int lowerLimit, int upperLimit)
00372 {
00373     int v;
00374     v = Property::getIntProperty(on, name, defaultVal);
00375     if(v < lowerLimit) return lowerLimit;
00376     if(v > upperLimit) return upperLimit;
00377     return v;
00378 }
00379 
00380 
00381 void Property::setIntProperty(Vobject& on, const string& name, int val,
00382         PropertyAccessControl* ac)
00383 {
00384     char num[64];
00385     snprintf(num, sizeof(num), "%d", val);
00386     Property::setProperty(on, name, num, "text/x-int", ac);
00387 }
00388 
00389 void Property::setIntProperty(Vobject& on, const string& name, int val,
00390         int lowerLimit, int upperLimit, PropertyAccessControl* ac)
00391 {
00392     if(val < lowerLimit) val = lowerLimit;
00393     if(val > upperLimit) val = upperLimit;
00394     Property::setIntProperty(on, name, val, ac);
00395 }
00396 
00397 
00398 
00399 double Property::getFloatProperty(Vobject& on, const string& name) {
00400     double v;
00401     string s;
00402     vRef<Property> p = meta_cast<Property*>(&(on.findObject(name)));
00403     if(!&p) throw bad_cast();
00404     p->read(s);
00405     sscanf(s.c_str(), "%lg", &v);
00406     return v;
00407 }
00408 
00409 bool Property::getBoolProperty(Vobject& on, const string& name) {
00410     string s;
00411     vRef<Property> p = meta_cast<Property*>(&(on.findObject(name)));
00412     if(!&p) throw bad_cast();
00413     p->read(s);
00414     if(s == "yes")
00415         return true;
00416     else
00417         return false;
00418 }
00419 
00420 
00421 double Property::getFloatProperty(Vobject& on, const string& name, double defaultVal) {
00422     double v = defaultVal;
00423     try {
00424         v = getFloatProperty(on, name);
00425     } catch(Vobject::NoSuchObjectError) {
00426         v = defaultVal;
00427     } catch(bad_cast) {
00428         v = defaultVal;
00429     }
00430     return v;
00431 }
00432 
00433 bool Property::getBoolProperty(Vobject& on, const string& name, bool defaultVal)
00434 {
00435     try {
00436         return getBoolProperty(on, name);
00437     } catch(NoSuchObjectError) {
00438         return defaultVal;
00439     } catch(bad_cast) {
00440         return defaultVal;
00441     }
00442     return defaultVal;
00443 }
00444 
00445 
00446 double Property::getFloatProperty(Vobject& on, const string& name, double defaultVal, double lowerLimit, double upperLimit) {
00447     double v = getFloatProperty(on, name, defaultVal);
00448     if(v < lowerLimit) return lowerLimit;
00449     if(v > upperLimit) return upperLimit;
00450     return v;
00451 }
00452 
00453 double Property::getFloatProperty(Vobject& on, const string& name, double lowLim, double upLim) {
00454     double v = getFloatProperty(on, name);
00455     if(v < lowLim) return lowLim;
00456     if(v > upLim) return upLim;
00457     return v;
00458 }
00459 
00460 
00461 
00462 void Property::setFloatProperty(Vobject& on, const string& name, double val,
00463         double lowerLimit, double upperLimit, PropertyAccessControl* ac) {
00464     if(val < lowerLimit) val = lowerLimit;
00465     if(val > upperLimit) val = upperLimit;
00466     setProperty(on, name, val, ac);
00467 }
00468 
00469 void Property::setFloatProperty(Vobject& on, const string& name, double val,
00470         PropertyAccessControl* ac) {
00471     setProperty(on, name, val, ac);
00472 }
00473 
00474 
00475 void Property::setBoolProperty(Vobject& on, const string& name, bool val,
00476         PropertyAccessControl* ac) {
00477     string s;
00478     if(val)
00479         s = "yes";
00480     else
00481         s = "no";
00482     setProperty(on, name, s, "text/x-yes-no", ac);
00483 }
00484 
00485 void Property::setFloatVectorProperty(Vobject& on, const string& name, vector<double> v, PropertyAccessControl* ac) {
00486     string s = "";  // TODO: reserve enough space for (v.size() * typical size of a double) chars.
00487     char c[256]; // TODO: find out max. number of digits in a double with 15 decimals.
00488     for(vector<double>::const_iterator i = v.begin(); i != v.end(); i++) {
00489         snprintf(c, sizeof(c), "%.15g", *i);
00490         s += c;
00491         if(i != v.end())
00492             s += " ";
00493     }
00494     setProperty(on, name, s, "text/x-vector/float", ac);
00495 }
00496 
00497 
00498 vector<double> Property::getFloatVectorProperty(Vobject& on, const string& name) {
00499     string::size_type start, end;
00500     start = end = 0;
00501     string s = getProperty(on, name);
00502     vector<double> v;
00503     const char* SEP = " \t,";
00504     while( ( start = s.find_first_not_of(SEP, start) ) != s.npos) {
00505         end = s.find_first_of(SEP, start);
00506         v.push_back( strtod( s.substr(start, end - start).c_str(), NULL ) );
00507         start = end + 1;
00508     }
00509     return v;
00510 }
00511 
00512 void Property::readFromFile(const string& filename, const string& type) {
00513     ifstream f(filename.c_str(), ios::in|ios::binary);
00514     if(!f.is_open() || f.bad())
00515         throw runtime_error(string("Error opening file \"") + filename + "\" for reading.");
00516     f.seekg(0, ios::end);
00517     unsigned long size = f.tellg();
00518     f.seekg(0, ios::beg);
00519     char* buffer = new char[size+1];
00520     f.read(buffer, size);
00521     f.close();
00522     string val(buffer, size);
00523     if(type == "")
00524         replace(val, getDataType());
00525     else
00526         replace(val, type);
00527     free(buffer);
00528 }
00529 
00530 void Property::writeStringToFile(const string& s, const string& filename) {
00531     ofstream f(filename.c_str(), ios::out|ios::binary);
00532     if(!f.is_open() || f.bad())
00533         throw runtime_error(string("Error opening file \"") + filename + "\" for writing.");
00534     f.write(s.c_str(), s.length());
00535     if(f.bad())
00536         throw runtime_error(string("Error writing to file \"")+filename+"\"");
00537 }
00538 
00539 
00540 void Property::writeToFile(const string& filename, int offset, int length)
00541 {
00542     string s;
00543     read(s, offset, length);
00544     writeStringToFile(s, filename);
00545 }
00546 
00547 void Property::writeRawToFile(const string& filename, int offset, int length)
00548 {
00549     string s;
00550     readRaw(s, offset, length);
00551     writeStringToFile(s, filename);
00552 }
00553 
00554 
00555 void DoNothingPropertySecurityInitializer::initializePropertyAccessControl(LocalProperty* p, Vobject& requester)
00556 {
00557     p->insertPropertyAccessControl(-1, &NoPropertyAccessControl::static_);
00558 }
00559 
00560 void Property::addPropertyListener(PropertyListener* pl, bool refresh)
00561 {
00562     propertyListeners[pl] = pl;
00563     if(RefCounted* rc = dynamic_cast<RefCounted*>(pl)) {
00564         rc->acquire(); // released by: removePropertyListener(), doExcise() or notifyObjectExcise()
00565         rc->addExciseListener(this);
00566     }
00567 }
00568 
00569 void Property::removePropertyListener(PropertyListener* pl)
00570 {
00571     if(propertyListeners.count(pl)) {
00572         propertyListeners.erase(pl);
00573         if(RefCounted* rc = dynamic_cast<RefCounted*>(pl)) {
00574             rc->removeExciseListener(this);
00575             rc->release(); // acquired by: addPropertyListener()
00576         }
00577     }
00578 }
00579 
00580 void Property::notifyObjectExcise(RefCounted* object)
00581 {
00582     if(Site* st = dynamic_cast<Site*>(object)) {
00583         PropertyListenerSiteWrapper plsw(st);
00584         PropertyListenerMap::iterator i = propertyListeners.find(&plsw);
00585         if(i != propertyListeners.end()) {
00586             removePropertyListener((*i).second);
00587             // st->removeExciseListener(this); -> redundant, since this object is being excised
00588             LOG("Property", 5, "going to delete plsw at " << (*i).second);
00589             PropertyListener* pl = (*i).second;
00590             delete pl;
00591         }
00592     }
00593     if(PropertyListener* pl = dynamic_cast<PropertyListener*>(object)) {
00594         removePropertyListener(pl);
00595     }
00596 }
00597 
00598 void Property::doExcise()
00599 {
00600     LOG("refcount", 3, "Begun excising property for " << getURL().getString() << " count is " << getCount());
00601     MetaObject::doExcise();
00602 
00603     for(PropertyListenerMap::iterator i = propertyListeners.begin();
00604         i != propertyListeners.end(); i++)
00605     {
00606         if(RefCounted* rc = dynamic_cast<RefCounted*>((*i).second)) {
00607             rc->removeExciseListener(this);
00608             rc->release(); // acquired by: addPropertyListener()
00609         }
00610         if(PropertyListenerSiteWrapper* plsw = dynamic_cast<PropertyListenerSiteWrapper*>((*i).second)) {
00611             delete plsw;
00612         }
00613     }
00614     propertyListeners.clear();
00615     LOG("refcount", 3, "Done excising property for " << getURL().getString());
00616     LOG("refcount", 3, "Count on this is " << getCount());
00617 }
00618 
00619 void Property::doSaveState(MessageBlock& output, set<string>& types, bool portable)
00620 {
00621     vRef<Message> m = new Message();
00622     m->setMethod("property:replace");
00623     m->insertField(-1, "data", readRaw(), true);
00624     m->insertField(-1, "datatype", getDataType(), true);
00625     output.insertMessage(-1, &m);
00626 }
00627 
00628 PropertyListener::~PropertyListener()
00629 {
00630 }
00631 
00632 PropertyListenerSiteWrapper::PropertyListenerSiteWrapper(Site* s)
00633     : site(s)
00634 {
00635     site->acquire(); // released by: destructor
00636 }
00637 
00638 PropertyListenerSiteWrapper::PropertyListenerSiteWrapper(Site* s, const string& fn)
00639     :  firstnonce(fn), site(s)
00640 {
00641     site->acquire(); // released by: destructor
00642 }
00643 
00644 PropertyListenerSiteWrapper::~PropertyListenerSiteWrapper()
00645 {
00646     LOG("plsw", 5, "deleting plsw " << site << " which wraps " << site->getURL().getString());
00647     site->release(); // acquired by: contructor
00648 }
00649 
00650 /*void PropertyListenerSiteWrapper::notifyPropertyWrite(Property& p, int start, const string& newpiece, const string& dtype)
00651 {
00652     vRef<Message> m = new Message();
00653     m->setType("update");
00654     m->setFrom(p.getURL().getString());
00655     m->setTo(site->getURL().getString());
00656     m->setMethod("property:update");
00657 
00658     char x[16];                // convert length (integer) to a string x...
00659     sprintf(x, "%i", start);
00660     m->insertField(-1, "start", string(x));
00661     m->insertField(-1, "data", newpiece);
00662     m->insertField(-1, "datatype", dtype);
00663 
00664     site->sendMessage(&m);
00665     }*/
00666 
00667 void PropertyListenerSiteWrapper::notifyPropertyChange(const PropertyEvent& event)
00668 {
00669     vRef<Message> m = new Message();
00670     m->setType("update");
00671     m->setFrom(event.getProperty()->getURL().getString());
00672     m->setTo(site->getURL().getString());
00673     m->setMethod("property:replace-update");
00674     if(firstnonce.size() > 0) {
00675         m->setNonce(firstnonce);
00676         firstnonce="";
00677     }
00678     m->insertField(-1, "data", event.getNewValue());
00679     m->insertField(-1, "datatype", event.getNewDataType());
00680     site->sendMessage(&m);
00681 }
00682 
00683 
00684 

Generated on Tue Aug 12 03:55:46 2003 for Interreality Project - VOS by doxygen 1.3.2