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/localproperty.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 
00027 #include <vos/corelibs/vos/vos.hh>
00028 #include "property.hh"
00029 #include <typechain/typechain.hh>
00030 
00031 #include <assert.h>
00032 
00033 /* LocalProperty */
00034 
00035 LocalProperty::LocalProperty(MetaObject* superobject)
00036     : MetaObject(superobject), Property(superobject)
00037 {
00038     addMessageHandler<LocalProperty>("property:get-length", this, &LocalProperty::getLengthHandler);
00039     addMessageHandler<LocalProperty>("property:read", this, &LocalProperty::readHandler);
00040     addMessageHandler<LocalProperty>("property:write", this, &LocalProperty::writeHandler);
00041     addMessageHandler<LocalProperty>("property:replace", this, &LocalProperty::replaceHandler);
00042     addMessageHandler<LocalProperty>("property:start-listening", this, &LocalProperty::startListeningHandler);
00043     addMessageHandler<LocalProperty>("property:stop-listening", this, &LocalProperty::stopListeningHandler);
00044 }
00045 
00046 LocalProperty::LocalProperty(MetaObject* superobject, const string& d, const string& dt)
00047     : MetaObject(superobject), Property(superobject)
00048 {
00049     raw_data = d;
00050     raw_datatype = dt;
00051     raw_length = raw_data.size();
00052 
00053     addMessageHandler<LocalProperty>("property:get-length", this, &LocalProperty::getLengthHandler);
00054     addMessageHandler<LocalProperty>("property:read", this, &LocalProperty::readHandler);
00055     addMessageHandler<LocalProperty>("property:write", this, &LocalProperty::writeHandler);
00056     addMessageHandler<LocalProperty>("property:replace", this, &LocalProperty::replaceHandler);
00057     addMessageHandler<LocalProperty>("property:start-listening", this, &LocalProperty::startListeningHandler);
00058     addMessageHandler<LocalProperty>("property:stop-listening", this, &LocalProperty::stopListeningHandler);
00059 }
00060 
00061 
00062 LocalProperty::~LocalProperty() {
00063 }
00064 
00065 
00066 void LocalProperty::setSecurityCallback(PropertySecurityInitializer* newcallback)
00067 {
00068     if(RefCounted* r = dynamic_cast<RefCounted*>(securitycallback)){
00069         r->release(); // acquired by: this method
00070     }
00071     if(RefCounted* r = dynamic_cast<RefCounted*>(newcallback)){
00072         r->acquire(); // released by: this method
00073     }
00074     securitycallback = newcallback;
00075 }
00076 
00077 
00078 
00079 void LocalProperty::write(Vobject& initiator, int start, const string& newdata)
00080 {
00081     string oldvalue;
00082     string newvalue;
00083     Property::read(oldvalue);
00084     Property::write(start, newdata);
00085     Property::read(newvalue);
00086 
00087     vRef<PropertyEvent> event = new PropertyEvent(PropertyEvent::PropertyWrite,
00088                                                   initiator, *this,
00089                                                   start, newdata.size(),
00090                                                   newvalue,
00091                                                   getDataType(),
00092                                                   oldvalue,
00093                                                   getDataType(),
00094                                                   false);
00095     
00096     for(PropertyListenerMap::iterator i = propertyListeners.begin(); i != propertyListeners.end(); i++) {
00097         (*i).second->notifyPropertyChange(*event);
00098     }
00099 }
00100 
00101 void LocalProperty::write(int start, const string& newdata)
00102 {
00103     write(*this, start, newdata);
00104 }
00105 
00106 
00107 void LocalProperty::replace(Vobject& initiator, const string& newdata, 
00108                             const string& newtype)
00109 {
00110     string oldvalue;
00111     string olddatatype;
00112     Property::read(oldvalue);
00113     olddatatype = Property::getDataType();
00114 
00115     Property::replace(newdata, newtype);
00116 
00117     vRef<PropertyEvent> event = new PropertyEvent(PropertyEvent::PropertyWrite,
00118                                                   initiator, *this,
00119                                                   newdata,
00120                                                   newtype,
00121                                                   oldvalue,
00122                                                   olddatatype,
00123                                                   false);
00124 
00125 
00126     for(PropertyListenerMap::iterator i = propertyListeners.begin(); i != propertyListeners.end(); i++) {
00127         (*i).second->notifyPropertyChange(*event);
00128     }
00129 }
00130 
00131 
00132 void LocalProperty::replace(const string& newdata, const string& newtype)
00133 {
00134     replace(*this, newdata, newtype);
00135 }
00136 
00137 void LocalProperty::getLengthHandler(Message* m)
00138 {
00139     vRef<Message> reply = new Message();
00140     LocalVobject::initReply(this, &reply, m, "property:length-update");
00141 
00142     vRef<Vobject> from = Vobject::findObjectFromRoot(m->getFrom());
00143 
00144     
00145     vRef<PropertyEvent> event = new PropertyEvent(PropertyEvent::PropertyRead,
00146                                                   *from, *this,
00147                                                   read(), 
00148                                                   getDataType(), 
00149                                                   true);
00150     string message;
00151     if(validatePropertyAccess(*event, message)) {
00152         char sz[16];
00153         sprintf(sz, "%i", getRawLength());
00154         reply->insertField(-1, "len", string(sz));
00155     } else {
00156         reply->insertField(-1, "error", message);
00157     }
00158 
00159     from->sendMessage(&reply);
00160 }
00161 
00162 void LocalProperty::readHandler(Message* m)
00163 {
00164     vRef<Message> reply = new Message();
00165     vRef<Vobject> from = Vobject::findObjectFromRoot(m->getFrom());
00166 
00167     int off=atoi(m->getField("start").value.c_str());
00168     int len=atoi(m->getField("length").value.c_str());
00169     if(off == 0 && len == -1) LocalVobject::initReply(this, &reply, m, "property:replace-update");
00170     else LocalVobject::initReply(this, &reply, m, "property:update");
00171 
00172 
00173     vRef<PropertyEvent> event = new PropertyEvent(PropertyEvent::PropertyRead,
00174                                                   *from, *this,
00175                                                   off, len,
00176                                                   read(), 
00177                                                   getDataType(),
00178                                                   true);
00179     string message;
00180 
00181     if(validatePropertyAccess(*event, message)) {
00182         string dat;
00183         readRaw(dat, off, len);
00184         reply->insertField(-1, "start", m->getField("start").value);
00185         reply->insertField(-1, "data", dat, true);
00186                   reply->insertField(-1, "datatype", getRawDataType(), true);
00187     } else {
00188         reply->insertField(-1, "error", message);
00189     }
00190 
00191     from->sendMessage(&reply);
00192 }
00193 
00194 void LocalProperty::writeHandler(Message* m)
00195 {
00196     vRef<Message> reply = new Message();
00197     LocalVobject::initReply(this, &reply, m, "property:update");
00198     vRef<Vobject> from = Vobject::findObjectFromRoot(m->getFrom());
00199     try {
00200         int off=atoi(m->getField("start").value.c_str());
00201         string f = m->getField("data").value;
00202 
00203         string precommit;
00204         readRaw(precommit);
00205         precommit.replace(off, f.size(), f);
00206 
00207         vRef<PropertyEvent> event = new PropertyEvent(
00208             PropertyEvent::PropertyWrite,
00209             *from, *this,
00210             off, f.size(),
00211             precommit, getDataType(),
00212             read(), getDataType(),
00213             true);
00214         string message;
00215         if(validatePropertyAccess(*event, message)) {
00216             vRef<Site> site = from->getSite();
00217             PropertyListenerSiteWrapper plsw(&site);
00218             PropertyListenerMap::iterator plsit = 
00219                 propertyListeners.find(&plsw);
00220             PropertyListener* plsw2 = 0;
00221             if(plsit != propertyListeners.end()) plsw2 = (*plsit).second;
00222             if(plsw2) propertyListeners.erase(plsw2);
00223             write(*from, off, f);
00224             if(plsw2) propertyListeners[plsw2] = plsw2;
00225             string d;
00226             readRaw(d, off, f.size());
00227             reply->insertField(-1, "data", d, true);
00228         } else {
00229             reply->insertField(-1, "error", message);
00230         }
00231     } catch(Message::NoSuchFieldError) {
00232         reply->insertField(-1, "error", "no data field");
00233     }
00234 
00235     from->sendMessage(&reply);
00236 }
00237 
00238 void LocalProperty::replaceHandler(Message* m)
00239 {
00240     vRef<Message> reply = new Message();
00241     if(m->getNonce() != "") LocalVobject::initReply(this, &reply, m, "property:replace-update");
00242 
00243     vRef<Vobject> from = Vobject::findObjectFromRoot(m->getFrom());
00244     try {
00245         string d = m->getField("data").value;
00246         string t = m->getField("datatype").value;
00247 
00248         vRef<PropertyEvent> event = new PropertyEvent(
00249             PropertyEvent::PropertyReplace,
00250             *from, *this,
00251             d, t,
00252             read(), getDataType(),
00253             true);
00254         string message;
00255 
00256         if(validatePropertyAccess(*event, message)) {
00257             vRef<Site> site = from->getSite();
00258             PropertyListenerSiteWrapper plsw(&site);
00259             PropertyListenerMap::iterator plsit = 
00260                 propertyListeners.find(&plsw);
00261             PropertyListener* plsw2 = 0;
00262             if(plsit != propertyListeners.end()) plsw2 = (*plsit).second;
00263             if(plsw2) propertyListeners.erase(plsw2);
00264             replace(*from, d, t);
00265             if(plsw2) propertyListeners[plsw2] = plsw2;
00266             string nd;
00267             readRaw(nd);
00268             if(m->getNonce() != "") {
00269                 reply->insertField(-1, "data", d, true);
00270                 reply->insertField(-1, "datatype", getRawDataType(), true);
00271             }
00272     } else {
00273             if(m->getNonce() != "") reply->insertField(-1, "error", message);
00274             LOG("property", 2, "permission denied to " << m->getFrom() << " to write to " << getURL().getString() << " (" << message << ")");
00275         }
00276     } catch(Message::NoSuchFieldError) {
00277         if(m->getNonce() != "") reply->insertField(-1, "error", "no data field");
00278     }
00279 
00280     if(m->getNonce() != "") from->sendMessage(&reply);
00281 }
00282 
00283 void LocalProperty::startListeningHandler(Message* m)
00284 {
00285     try {
00286         for(int i = 0; i < m->getNumFields(); i++) {
00287             if(m->getField(i).key == "listen"
00288                && m->getField(i).value == "property") {
00289                 vRef<Site> st = m->getSourceSite();
00290 
00291                 vRef<PropertyEvent> event = 
00292                     new PropertyEvent(PropertyEvent::PropertyRead,
00293                                       *st, *this,
00294                                       read(), 
00295                                       getDataType(),
00296                                       true);
00297                 string message;
00298                 if(validatePropertyAccess(*event, message)) {
00299                     vRef<Message> reply = new Message();
00300                     LocalVobject::initReply(this, &reply, m, "property:start-listening-reply");
00301                     reply->setNonce(m->getNonce() + string("-1"));
00302                     reply->insertField(-1, "listen", "property");
00303                     vRef<Vobject> from = findObject(m->getFrom());
00304                     from->sendMessage(&reply);
00305 
00306                     PropertyListenerSiteWrapper* pl = new PropertyListenerSiteWrapper(&st, m->getNonce());
00307                     LOG("Property", 5, "allocated plsw at " << pl);
00308 
00309                     addPropertyListener(pl);
00310                     st->addExciseListener(this);
00311                 } else {
00312                 }
00313             break;
00314         }
00315     }
00316     } catch(Message::NoSuchFieldError) {
00317     } catch(NoSuchObjectError) { }
00318 }
00319 
00320 void LocalProperty::stopListeningHandler(Message* m)
00321 {
00322     try {
00323         if(m->getField("listen").value == "property") {
00324             PropertyListenerMap::iterator i;
00325             vRef<Site> st = m->getSourceSite();
00326             PropertyListenerSiteWrapper plsw(&st);
00327             i = propertyListeners.find(&plsw);
00328             if(i != propertyListeners.end()) {
00329                 removePropertyListener((*i).second);
00330                 st->removeExciseListener(this);
00331                 LOG("Property", 4, "aha did a stop-listening here! " << (*i).second);
00332                 delete (*i).second;
00333             }
00334         }
00335     } catch(Message::NoSuchFieldError) { }
00336 }
00337 
00338 MetaObject* LocalProperty::new_LocalProperty(MetaObject* superobject, const string& type)
00339 {
00340     return new LocalProperty(superobject);
00341 }
00342 
00343 void LocalProperty::addPropertyListener(PropertyListener* pl, bool refresh)
00344 {
00345     Property::addPropertyListener(pl, refresh);
00346     if(refresh) {
00347         string d;
00348         read(d);
00349         vRef<PropertyEvent> event = 
00350             new PropertyEvent(PropertyEvent::PropertyReplace,
00351                               *this, *this, d, getDataType(), false);
00352 
00353         pl->notifyPropertyChange(*event);
00354     }
00355 }
00356 
00357 void LocalProperty::initializeSecurity(Vobject& requester)
00358 {
00359     LOG("LocalProperty", 4, "initializing security on this property with requester "
00360          << requester.getURL().getString());
00361     securitycallback->initializePropertyAccessControl(this, requester);
00362 }
00363 
00364 
00365 void LocalProperty::insertPropertyAccessControl(int pos, PropertyAccessControl* ac)
00366 {
00367     if(pos < 0) pos += accesscontrols.size() + 1;
00368     accesscontrols.insert(accesscontrols.begin() + pos, ac);
00369 }
00370 
00371 void LocalProperty::insertPropertyAccessControl(int pos, const string& policyname)
00372 {
00373     if(pos < 0) pos += accesscontrols.size() + 1;
00374 
00375     PropertyAccessControl* ac = PropertyAccessControl::getPolicy(policyname, this);
00376     if(ac) accesscontrols.insert(accesscontrols.begin() + pos, ac);
00377 }
00378 
00379 void LocalProperty::removePropertyAccessControl(int pos)
00380 {
00381     if(pos < 0) pos += accesscontrols.size() + 1;
00382     accesscontrols.erase(accesscontrols.begin() + pos);
00383 }
00384 
00385 void LocalProperty::removePropertyAccessControl(PropertyAccessControl* ac)
00386 {
00387     for(unsigned int i = 0; i < accesscontrols.size(); i++) {
00388         if(accesscontrols[i] == ac) {
00389             accesscontrols.erase(accesscontrols.begin() + i);
00390             i--;
00391         }
00392     }
00393 }
00394 
00395 void LocalProperty::removePropertyAccessControl(const string& policyname)
00396 {
00397     for(unsigned int i = 0; i < accesscontrols.size(); i++) {
00398         if(accesscontrols[i]->getPolicyName() == policyname) {
00399             accesscontrols.erase(accesscontrols.begin() + i);
00400             i--;
00401         }
00402     }
00403 }
00404 
00405 const deque<PropertyAccessControl*>& LocalProperty::getPropertyAccessControls()
00406 {
00407     return accesscontrols;
00408 }
00409 
00410 bool LocalProperty::validatePropertyAccess(PropertyEvent& e, string& message)
00411 {
00412     if(accesscontrols.size() == 0) {
00413         message = "Error in access policy list.  Permission denied by default.";
00414         LOG("localproperty", 1, "Access policy list for "
00415             << e.getProperty()->getURL().getString() << " is empty!");
00416         return false;
00417     }
00418 
00419     for(unsigned int i = 0; i < accesscontrols.size(); i++) {
00420         if(! accesscontrols[i]) {
00421             message = "Error in access policy list.  Permission denied by default.";
00422             LOG("localvobject", 1, "Access policy list "
00423                 << e.getProperty()->getURL().getString() << " contains an invalid (null) policy!");
00424             return false;
00425         }
00426         switch(e.getEvent()) {
00427         case PropertyEvent::PropertyWrite:
00428         case PropertyEvent::PropertyReplace:
00429             if(! accesscontrols[i]->checkChangePermission(e, message)) return false;
00430             break;
00431         case PropertyEvent::PropertyRead:
00432             if(! accesscontrols[i]->checkReadPermission(e, message)) return false;
00433             break;
00434         default:
00435             message = "Supplied validateAccess with an unsupported event type!";
00436             LOG("localvobject", 1, "Supplied validateAccess with an unsupported event type " << e.getEvent());
00437             return false;
00438         }
00439     }
00440     return true;
00441 }

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