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

vos/corelibs/vos/vobject.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-2003 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 
00024 #include "vobject.hh"
00025 #include "listener.hh"
00026 #include "site.hh"
00027 #include "message.hh"
00028 
00029 using namespace VOS;
00030 
00031 #include <stdio.h>
00032 #include <signal.h>
00033 
00034 #include <string>
00035 #include <algorithm>
00036 #include <typeinfo>
00037 
00038 /** @file
00039     Implements VobjectImplementation.
00040 */
00041 
00042 bool VobjectImplementation::queueMsgs_def=false;
00043 bool VobjectImplementation::queueUpdateMsgs_def=false;
00044 
00045 DoNothingListener DoNothingListener::static_;
00046 
00047 bool Vobject::operator==(Vobject& v) {
00048     bool ret;
00049     rREF(Site&, ts, getSite(),
00050          rREF(Site&, vs, v.getSite(),
00051               ret = (((void*)&ts == (void*)&vs) && getName() == v.getName());
00052              );
00053         );
00054     return ret;
00055 }
00056 
00057 bool Vobject::operator==(Vobject* v) {
00058     bool ret;
00059     rREF(Site&, ts, getSite(),
00060          rREF(Site&, vs, v->getSite(),
00061               ret = (((void*)&ts == (void*)&vs) && getName() == v->getName());
00062              );
00063         );
00064     return ret;
00065 }
00066 
00067 VobjectImplementation::VobjectImplementation(const string& n, Site* s, bool islocalobj)
00068     :  islocal(islocalobj), exciseCalled(false), site(s), name(n),
00069        queueMsgs(queueMsgs_def), queueUpdateMsgs(queueUpdateMsgs_def)
00070 {
00071     if(site) {
00072         url=site->getURL();
00073         url.setPath("/" + name);
00074         site->acquire(); // released by: excise() or destructor
00075     }
00076 }
00077 
00078 VobjectImplementation::~VobjectImplementation()
00079 {
00080     LOG("Vobject", 3, "deleting " << url.getString());
00081 
00082     if(site) {
00083         LOG("refcount", 5, "count on site " << site->getURL().getString() << " is " << site->getCount());
00084         site->release(); // acquired by: constructor
00085     }
00086 
00087     for(set<ParentChangeListener*>::iterator i = parentListeners.begin(); i != parentListeners.end(); i++) {
00088         if(RefCounted* rc = dynamic_cast<RefCounted*>(*i)) {
00089             rc->removeExciseListener(this, false);
00090             rc->release();
00091         }
00092     }
00093     for(set<ChildChangeListener*>::iterator i = childListeners.begin(); i != childListeners.end(); i++) {
00094         if(RefCounted* rc = dynamic_cast<RefCounted*>(*i)) {
00095             rc->removeExciseListener(this, false);
00096             rc->release();
00097         }
00098     }
00099     for(set<TypeChangeListener*>::iterator i = typeListeners.begin(); i != typeListeners.end(); i++) {
00100         if(RefCounted* rc = dynamic_cast<RefCounted*>(*i)) {
00101             rc->removeExciseListener(this, false);
00102             rc->release();
00103         }
00104     }
00105 }
00106 
00107 Site& VobjectImplementation::getSite() {
00108     site->acquire(); // released by: the caller of this method
00109     return *site;
00110 }
00111 
00112 const set<string>& VobjectImplementation::getTypes() throw (AccessControlError, RemoteError)
00113 { return types; }
00114 
00115 const set<Vobject::ParentChildRelation*,
00116           Vobject::ParentChildRelation::Cmp>& VobjectImplementation::getParents()
00117     throw (AccessControlError, RemoteError)
00118 { return parents; }
00119 
00120 const deque<Vobject::ParentChildRelation*>& VobjectImplementation::getChildren()
00121     throw (AccessControlError, RemoteError)
00122 { return children; }
00123 
00124 Vobject& Vobject::findObjectFromRoot(const string& path)
00125     throw (NoSuchSiteError, NoSuchObjectError, URL::BadURLError, AccessControlError, RemoteError)
00126 {
00127     if(path.substr(0, 6) != "vop://") throw NoSuchObjectError("Object path doesn't start with vop://");
00128     URL u(path);
00129     string s;
00130     s += u.getHostAndPort();
00131     Site& objsite=Site::findSite(s);
00132 
00133     if(u.getPath() == "") {
00134         // pass reference through
00135         return objsite;
00136     } else {
00137         // pass reference to 'v' through
00138         try {
00139             Vobject& v = objsite.findObject(u.getPath());
00140             objsite.release(); // acquired by: findSite() above
00141             return v;
00142         } catch(...) {
00143             objsite.release(); // acquired by: findSite() above
00144             throw;
00145         }
00146     }
00147 }
00148 
00149 Vobject::ParentChildRelation& VobjectImplementation::findChild(const string& path)
00150     throw (NoSuchObjectError, AccessControlError, RemoteError)
00151 {
00152     if(path[0] == '#') {
00153         int pos=atoi(path.substr(1).c_str());
00154         if(pos < 0) pos = (int)children.size() + pos;
00155         if((unsigned int)pos >= children.size()) throw NoSuchObjectError(string("Object position out of range: \"") +  path + "\"");
00156         Vobject::ParentChildRelation* child=children[pos];
00157         if(child == 0) throw NoSuchObjectError("Object at position not aquired (BUG!)");
00158         child->acquire(); // released by: the caller of this method
00159         return *child;
00160     } else {
00161         map<string, Vobject::ParentChildRelation*>::iterator it=children_map.find(path);
00162         if(it == children_map.end()) throw NoSuchObjectError(string("No object by that name: \"") + path + "\"");
00163         ((*it).second)->acquire(); // released by: the caller of this method
00164         return *((*it).second);
00165     }
00166 }
00167 
00168 Vobject::ParentChildRelation& VobjectImplementation::findParent(Vobject& parent)
00169     throw (NoSuchObjectError, AccessControlError, RemoteError)
00170 {
00171     for(set<Vobject::ParentChildRelation*, Vobject::ParentChildRelation::Cmp>::const_iterator piter = getParents().begin();
00172           piter != parents.end();
00173           piter++) {
00174         //LOG("Vobject", 5, "comparing " << (*piter)->parent->getSite().getURL().getString() << " to " << parent.getSite().getURL().getString());
00175         //LOG("Vobject", 5, "comparing " << (*piter)->parent->getName() << " to " << parent.getName());
00176         if(*((*piter)->parent) == parent) {
00177             (*piter)->acquire(); // released by: the caller of this method
00178             return **piter;
00179         }
00180     }
00181     throw NoSuchObjectError("Supplied object is not a parent");
00182 }
00183 
00184 Vobject& VobjectImplementation::findObject(const string& path)
00185     throw (NoSuchSiteError, NoSuchObjectError, URL::BadURLError, AccessControlError, RemoteError)
00186 {
00187     if(path.substr(0, 6) == "vop://") {
00188         // pass reference through
00189         return findObjectFromRoot(path);
00190     }
00191     if(path == "") {
00192         acquire(); // released by: the caller of this method
00193         return *this;
00194     }
00195     if(path == "/" ) throw NoSuchObjectError("\"/\" is not a legal path");
00196     unsigned int nextpart;
00197     if(path[0] == '/') {
00198         // pass reference through
00199         rREF(Site&, site, getSite(),
00200              Vobject& v = site.findObject(path.substr(1));
00201              site.release(); // acquired by: getSite() above
00202              return v;
00203             ); // will catch any exceptions, release the site, and re-throw the exception
00204     }
00205     nextpart = (unsigned int)path.find("/");
00206     string cur=path.substr(0, nextpart);
00207     string rest;
00208     if(nextpart != string::npos) rest=path.substr(nextpart+1);
00209 
00210     Vobject* child;
00211     rREF(Vobject::ParentChildRelation&, pcr, findChild(cur), child = pcr.child);
00212     if(! child) throw NoSuchObjectError("Object not available");
00213     if(rest == "") {
00214         child->acquire(); // released by: the caller of this method
00215         return *child;
00216     } else {
00217         // pass reference through
00218         return child->findObject(rest);
00219     }
00220 }
00221 
00222 void VobjectImplementation::insertChild(Vobject* requester, int pos, const string& context_name, Vobject* child)
00223     throw (AccessControlError, RemoteError)
00224 {
00225 
00226     if(pos < 0) pos = (int)children.size() + pos + 1;
00227 
00228     if(MetaObject* m = dynamic_cast<MetaObject*>(child)) {
00229         child=m->getTopObject();
00230     }
00231 
00232     vRef<Site> thissite = getSite();
00233 
00234     vRef<Vobject::ParentChildRelation> c = new Vobject::ParentChildRelation(child, this);
00235     c->position=pos;
00236     c->contextual_name=context_name;
00237 
00238     if(children.size() < (unsigned int)pos) {
00239         children.resize(pos, 0);
00240     }
00241 
00242     c->acquire(); // released by: removeChild() or setChild()
00243     // since both children and children_map[] are manipulated in
00244     // parallel, consider it a single reference
00245     children.insert(children.begin()+pos, &c);
00246     if(!children_map.count(context_name) || pos < children_map[context_name]->position) {
00247         children_map[context_name]=&c;
00248     }
00249 
00250     for(unsigned int i=pos+1; i < children.size(); i++) {
00251         if(children[i]) children[i]->position++;
00252     }
00253 
00254     if(VobjectImplementation* v = dynamic_cast<VobjectImplementation*>(child)) {
00255         /* because the child now has a reference to c as well */
00256         c->acquire(); // released by: removeChild() or setChild()
00257         v->parents.insert(&c);
00258 
00259         vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ParentInsert, *requester,
00260                                                     *this, pos, context_name, *child);
00261 
00262         for(set<ParentChangeListener*>::iterator i = v->parentListeners.begin();
00263             i != v->parentListeners.end(); i++)
00264         {
00265             thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00266         }
00267         LOG("insertChild", 3, "did add " << c->parent->getURL().getString() << " as a parent for "
00268             << c->child->getURL().getString() << "(count " << c->child->getCount()
00269             << ") at position " << pos << ", size of parents is " << (unsigned int)v->parents.size());
00270     }
00271 
00272     vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ChildInsert, *requester,
00273                                                 *this, pos, context_name, *child);
00274 
00275     for(set<ChildChangeListener*>::iterator i = childListeners.begin();
00276         i != childListeners.end(); i++)
00277     {
00278         thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00279     }
00280 }
00281 
00282 
00283 void VobjectImplementation::setChild(Vobject* requester, int position, const string& contextual_name, Vobject* child)
00284     throw (AccessControlError, RemoteError)
00285 {
00286     if(! child) return;
00287     assert(requester);
00288     if(position < 0) position = (int)children.size() + position;
00289 
00290     if(MetaObject* m = dynamic_cast<MetaObject*>(child)) {
00291         child=m->getTopObject();
00292     }
00293 
00294     LOG("vobject", 5, "position " << position << "  size " << (unsigned int)children.size());
00295     if(children.size() > (unsigned int)position) {
00296         LOG("vobject", 5, "oldedge is " << children[position]);
00297     }
00298     else {
00299         LOG("vobject", 5, "position doesn't fit");
00300     }
00301 
00302     if(children.size() <= (unsigned int)position) {
00303         children.resize(position+1, 0);
00304     }
00305 
00306     Vobject* oldchild = 0;
00307 
00308     vRef<Site> thissite = getSite();
00309 
00310     ParentChildRelation* oldedge = children[position];
00311     LOG("vobject", 4, "entered setChild on " << getURL().getString() << " for child " << child->getURL().getString()
00312         << "(" << contextual_name << ")" << " and oldedge is " << oldedge);
00313     if(oldedge) {
00314         if(oldedge->child == child && oldedge->contextual_name == contextual_name) {
00315             LOG("vobject", 4, "new child/pos/contextname same as old one.  sending notifications but otherwise ignoring");
00316 
00317             vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ChildReplace,
00318                                                         *requester, *this, position, contextual_name,
00319                                                         *child, *(oldedge->child));
00320 
00321             for(set<ChildChangeListener*>::iterator i = childListeners.begin();
00322                 i != childListeners.end(); i++)
00323             {
00324                 thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00325             }
00326             thissite->flushNotifications();
00327             return;
00328         }
00329 
00330         oldedge->child->acquire(); // released below (after doing notifications)
00331         oldchild = oldedge->child;
00332 
00333         if(VobjectImplementation* v = dynamic_cast<VobjectImplementation*>(oldedge->child)) {
00334             vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ParentRemove,
00335                                                         *requester, *this, oldedge->position,
00336                                                         oldedge->contextual_name, *(oldedge->child));
00337             v->parents.erase(children[position]);
00338             for(set<ParentChangeListener*>::iterator i = v->parentListeners.begin();
00339                 i != v->parentListeners.end(); i++)
00340             {
00341                 thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00342             }
00343         }
00344 
00345         LOG("vobject", 5, "about to release oldedge twice, count is " << oldedge->getCount());
00346 
00347         /* release twice, once for parent, once for child */
00348         oldedge->release(); // acquired by: insertChild() or setChild()
00349         oldedge->release(); // acquired by: insertChild() or setChild()
00350     }
00351 
00352     LOG("vobject", 5, "about to create a pcr, count on child is " << getCount());
00353     vRef<Vobject::ParentChildRelation> c = new Vobject::ParentChildRelation(child, this);
00354 
00355     c->position=position;
00356     c->contextual_name=contextual_name;
00357 
00358     c->acquire(); // released by: removeChild() or setChild()
00359     // since both children and children_map[] are manipulated in
00360     // parallel, consider it a single reference
00361     children[position]=&c;
00362     if(!children_map.count(contextual_name) || position <= children_map[contextual_name]->position) {
00363         children_map[contextual_name]=&c;
00364     }
00365 
00366     if(VobjectImplementation* v = dynamic_cast<VobjectImplementation*>(child)) {
00367         /* because the child now has a reference to c as well */
00368         c->acquire(); // released by: setChild() or removeChild()
00369         v->parents.insert(&c);
00370 
00371         vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ParentInsert,
00372                                                     *requester, *this, position,
00373                                                     contextual_name, *child);
00374 
00375         for(set<ParentChangeListener*>::iterator i = v->parentListeners.begin();
00376             i != v->parentListeners.end(); i++)
00377         {
00378             thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00379         }
00380 
00381         LOG("setChild", 4, "did add " << c->parent->getURL().getString() << " as a parent for "
00382             << child->getURL().getString() << " at position " << position << ", size of parents is "
00383             << (unsigned int)v->parents.size() << ", and size of children " << (unsigned int)children.size());
00384     }
00385 
00386     if(oldchild) {
00387         vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ChildReplace,
00388                                                     *requester, *this, position, contextual_name,
00389                                                     *child, *oldchild);
00390 
00391         for(set<ChildChangeListener*>::iterator i = childListeners.begin();
00392             i != childListeners.end(); i++)
00393         {
00394             thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00395         }
00396         oldchild->release(); // acquired above (when releasing old edge)
00397     } else {
00398         vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ChildInsert,
00399                                                     *requester, *this, position, contextual_name,
00400                                                     *child);
00401 
00402         for(set<ChildChangeListener*>::iterator i = childListeners.begin();
00403             i != childListeners.end(); i++)
00404         {
00405             thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00406         }
00407     }
00408 
00409     thissite->flushNotifications();
00410 
00411     LOG("setChild", 4, getURL().getString() << " children.size() == " << (unsigned int)children.size());
00412 }
00413 
00414 
00415 void VobjectImplementation::removeChild(Vobject* requester, int pos)
00416     throw (AccessControlError, RemoteError)
00417 {
00418     if(pos < 0) pos = (int)children.size() + pos;
00419     if((unsigned int)pos >= children.size()) pos = pos % (int)children.size();
00420     vRef<Vobject::ParentChildRelation> c = children[pos];
00421 
00422     children.erase(children.begin() + pos);
00423 
00424     if(&c) {
00425         if(children_map[c->contextual_name]->position == c->position) {
00426             bool mapNext = false;
00427             unsigned int i;
00428             for(i = c->position; i < children.size(); i++) {
00429                 if(children[i]->contextual_name == c->contextual_name) {
00430                     mapNext = true;
00431                     break;
00432                 }
00433             }
00434             if(mapNext) {
00435                 children_map[c->contextual_name] = children[i];
00436             } else children_map.erase(c->contextual_name);
00437         }
00438 
00439         for(unsigned int i=pos; i < children.size(); i++) {
00440             if(children[i]) children[i]->position--;
00441         }
00442 
00443         string context_name = c->contextual_name;
00444         Vobject* child = c->child;
00445 
00446         if(MetaObject* m = dynamic_cast<MetaObject*>(child)) {
00447             child=m->getTopObject();
00448         }
00449 
00450         vRef<Site> thissite = getSite();
00451 
00452         if(VobjectImplementation* v = dynamic_cast<VobjectImplementation*>(child)) {
00453             v->parents.erase(&c);
00454             c->release(); // acquired by: insertChild() or setChild()
00455 
00456             vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ParentRemove, *requester, *this,
00457                                                         c->position, c->contextual_name, *child);
00458 
00459             for(set<ParentChangeListener*>::iterator i = v->parentListeners.begin();
00460                 i != v->parentListeners.end(); i++)
00461             {
00462                 thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00463             }
00464         }
00465 
00466         vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ChildRemove, *requester,
00467                                                     *this, pos, context_name, *child);
00468 
00469         if(child) {
00470             for(set<ChildChangeListener*>::iterator i = childListeners.begin();
00471                 i != childListeners.end(); i++)
00472             {
00473                 thissite->addNotification(new VobjectNotifyEvent(*i, *event));
00474             }
00475         }
00476         thissite->flushNotifications();
00477     }
00478 }
00479 
00480 bool VobjectImplementation::hasMessageAvailable()
00481 {
00482     return (!incomingMessageQueue.empty());
00483 }
00484 
00485 /* get the next message this object has received */
00486 Message* VobjectImplementation::receiveMessage() throw (MessageQueueEmptyError)
00487 {
00488     Message* m;
00489     if(incomingMessageQueue.empty()) throw MessageQueueEmptyError("No messages available");
00490     m = incomingMessageQueue.front();
00491     incomingMessageQueue.pop_front();
00492     // pass the reference through
00493     return m;
00494 }
00495 
00496 void VobjectImplementation::sendUpdateMessage(Message* m)
00497 {
00498     if(queueUpdateMsgs) {
00499         m->acquire(); // released by: the caller of receiveUpdateMessage()
00500         incomingUpdateMessageQueue.push_back(m);
00501         // do not release "m" because we are holding onto
00502         // a reference to it
00503     }
00504 }
00505 
00506 Message* VobjectImplementation::receiveUpdateMessage() throw (MessageQueueEmptyError)
00507 {
00508     Message* m;
00509     if(incomingUpdateMessageQueue.empty()) throw MessageQueueEmptyError("No messages available");
00510     m = incomingUpdateMessageQueue.front();
00511     incomingUpdateMessageQueue.pop_front();
00512     return m;
00513     // do not release because we are implicitly transfering
00514     // the acquire from incomingMessageQueue to the calling method
00515 }
00516 
00517 bool VobjectImplementation::hasUpdateMessageAvailable()
00518 {
00519     return (!incomingUpdateMessageQueue.empty());
00520 }
00521 
00522 void VobjectImplementation::addTypeListener(TypeChangeListener* tl, bool refresh)
00523 {
00524     if(RefCounted* rc = dynamic_cast<RefCounted*>(tl)) {
00525         rc->acquire(); // released by: removeTypeListener() or this destructor
00526         rc->addExciseListener(this);
00527     }
00528     typeListeners.insert(tl);
00529 
00530     if(refresh) {
00531         TypeSet tmptypeset = types;
00532         for(set<string>::iterator it = tmptypeset.begin();
00533             it != tmptypeset.end(); it++) {
00534             try {
00535                 vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::TypeInsert, *this, *this, (*it));
00536                 tl->notifyTypeInserted(*event);
00537             } catch(runtime_error x) {
00538                 LOG("vobject", 0, "call to notifyTypeInserted emitted exception: " << x.what());
00539             } catch(...) { }
00540         }
00541     }
00542 }
00543 
00544 void VobjectImplementation::addParentListener(ParentChangeListener* pl, bool refresh)
00545 {
00546     if(RefCounted* rc = dynamic_cast<RefCounted*>(pl)) {
00547         rc->acquire(); // released by: removeParentListener() or this destructor
00548         rc->addExciseListener(this);
00549     }
00550     parentListeners.insert(pl);
00551 
00552     if(refresh) {
00553         ParentSet tmpparentset = parents;
00554         for(set<ParentChildRelation*, ParentChildRelation::Cmp>::iterator it = tmpparentset.begin();
00555             it != tmpparentset.end(); it++) {
00556             try {
00557                 if((*it)->parent) {
00558                     vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ParentInsert, *this,
00559                                                                 *((*it)->parent), (*it)->position,
00560                                                                 (*it)->contextual_name, *this);
00561                     pl->notifyParentInserted(*event);
00562                 }
00563             } catch(runtime_error x) {
00564                 LOG("vobject", 0, "call to notifyParentInserted emitted exception: " << x.what());
00565             } catch(...) { }
00566         }
00567     }
00568 }
00569 
00570 void VobjectImplementation::addChildListener(ChildChangeListener* cl, bool refresh)
00571 {
00572     if(RefCounted* rc = dynamic_cast<RefCounted*>(cl)) {
00573         rc->acquire(); // released by: removeChildListener() or this destructor
00574         rc->addExciseListener(this);
00575     }
00576     childListeners.insert(cl);
00577 
00578     if(refresh) {
00579         ChildList cc = children;
00580         for(unsigned int it = 0; it < cc.size(); it++) {
00581             if(cc[it]) cc[it]->acquire();
00582         }
00583         for(unsigned int it = 0; it < cc.size(); it++) {
00584             if(cc[it]) {
00585                 if(cc[it]->getCount() > 1) {
00586                     try {
00587                         ParentChildRelation* pcr = cc[it];
00588                         if(pcr->child) {
00589                             vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::ChildInsert, *this,
00590                                                                         *this, pcr->position,
00591                                                                         pcr->contextual_name,
00592                                                                         *(pcr->child));
00593                             cl->notifyChildInserted(*event);
00594                         }
00595                     } catch(runtime_error x) {
00596                         LOG("vobject", 0, "call to notifyChildInserted emitted exception: " << x.what());
00597                     } catch(...) {
00598                         LOG("vobject", 0, "call to notifyChildInserted emitted unknown exception!");
00599                     }
00600                 }
00601                 cc[it]->release();
00602             }
00603         }
00604     }
00605 }
00606 
00607 void VobjectImplementation::removeTypeListener(TypeChangeListener* tl)
00608 {
00609     if(typeListeners.count(tl)) {
00610         typeListeners.erase(tl);
00611         if(RefCounted* rc = dynamic_cast<RefCounted*>(tl)) {
00612             rc->removeExciseListener(this);
00613             rc->release(); // acquired by: addTypeListener()
00614         }
00615     }
00616 }
00617 
00618 void VobjectImplementation::removeParentListener(ParentChangeListener* pl)
00619 {
00620     if(parentListeners.count(pl)) {
00621         parentListeners.erase(pl);
00622         if(RefCounted* rc = dynamic_cast<RefCounted*>(pl)) {
00623             rc->removeExciseListener(this);
00624             rc->release(); // acquired by: addParentListener()
00625         }
00626     }
00627 }
00628 
00629 void VobjectImplementation::removeChildListener(ChildChangeListener* cl)
00630 {
00631     if(childListeners.count(cl)) {
00632         childListeners.erase(cl);
00633         if(RefCounted* rc = dynamic_cast<RefCounted*>(cl)) {
00634             rc->removeExciseListener(this);
00635             rc->release(); // acquired by: addChildListener()
00636         }
00637     }
00638 }
00639 
00640 void VobjectImplementation::notifyObjectExcise(RefCounted* rc)
00641 {
00642     if(TypeChangeListener* tl = dynamic_cast<TypeChangeListener*>(rc)) removeTypeListener(tl);
00643     if(ParentChangeListener* pl = dynamic_cast<ParentChangeListener*>(rc)) removeParentListener(pl);
00644     if(ChildChangeListener* cl = dynamic_cast<ChildChangeListener*>(rc)) removeChildListener(cl);
00645 
00646     for(HandlerMap::iterator it = msghandlers.begin(); it != msghandlers.end(); ) {
00647         if((*it).second->holds(rc)) {
00648             HandlerMap::iterator tmp = it;
00649             delete (*it).second;
00650             it++;
00651             msghandlers.erase(tmp);
00652         } else it++;
00653     }
00654     for(HandlerMap::iterator it = updatehandlers.begin(); it != updatehandlers.end(); ) {
00655         if((*it).second->holds(rc)) {
00656             HandlerMap::iterator tmp = it;
00657             delete (*it).second;
00658             it++;
00659             updatehandlers.erase(tmp);
00660         } else it++;
00661     }
00662 }
00663 
00664 void VobjectImplementation::addType(Vobject* requester, const string& s)
00665 {
00666     if(s != "" && !types.count(s)) {
00667         types.insert(s);
00668 
00669         vRef<VobjectEvent> event = new VobjectEvent(VobjectEvent::TypeInsert, *requester, *this, s);
00670 
00671         for(set<TypeChangeListener*>::iterator i = typeListeners.begin();
00672             i != typeListeners.end();
00673             i++)
00674         {
00675             try {
00676                 (*i)->notifyTypeInserted(*event);
00677             } catch(runtime_error x) {
00678                 LOG("refcount", 0, "call to notifyTypeInserted emitted exception: " << x.what());
00679             } catch(...) { }
00680         }
00681     }
00682 }
00683 
00684 void VobjectImplementation::excise()
00685 {
00686     if(exciseCalled) return;
00687     else exciseCalled = true;
00688 
00689     RefCounted::excise();
00690 
00691     //if(site) site->release(); // acquired by: constructor
00692     //site=0;
00693 
00694     for(int i = (int)children.size() - 1; i >= 0; i--) {
00695         VobjectImplementation::removeChild(this, i);
00696     }
00697 
00698     // copy it so as to avoid concurrently modifying the _same_ set object, which would be baaaaad.
00699     set<ParentChildRelation*, Vobject::ParentChildRelation::Cmp> parentbuf = parents;
00700     LOG("Vobject", 4, "parents size is " << (unsigned int)parentbuf.size());
00701     for(set<ParentChildRelation*, Vobject::ParentChildRelation::Cmp>::iterator it = parentbuf.begin();
00702         it != parentbuf.end();
00703         it++) {
00704         LOG("Vobject", 4, "parents size is " << (unsigned int)parents.size());
00705         try {
00706             if(VobjectImplementation* p = dynamic_cast<VobjectImplementation*>((*it)->parent)) {
00707                 LOG("Vobject", 4, "removing parent " << p->getURL().getString() << " of child " << getURL().getString());
00708                 if(p->isRemote()) p->setChild(this, (*it)->position, (*it)->contextual_name, 0);
00709                 else p->VobjectImplementation::removeChild(this, (*it)->position);
00710             }
00711         } catch(AccessControlError) { }
00712     }
00713 
00714     for(set<ParentChangeListener*>::iterator i = parentListeners.begin(); i != parentListeners.end(); i++) {
00715         if(RefCounted* rc = dynamic_cast<RefCounted*>(*i)) {
00716             rc->removeExciseListener(this);
00717             rc->release();
00718         }
00719     }
00720     for(set<ChildChangeListener*>::iterator i = childListeners.begin(); i != childListeners.end(); i++) {
00721         if(RefCounted* rc = dynamic_cast<RefCounted*>(*i)) {
00722             rc->removeExciseListener(this);
00723             rc->release();
00724         }
00725     }
00726     for(set<TypeChangeListener*>::iterator i = typeListeners.begin(); i != typeListeners.end(); i++) {
00727         if(RefCounted* rc = dynamic_cast<RefCounted*>(*i)) {
00728             rc->removeExciseListener(this);
00729             rc->release();
00730         }
00731     }
00732     parentListeners.clear();
00733     childListeners.clear();
00734     typeListeners.clear();
00735 
00736     for(HandlerMap::iterator it = msghandlers.begin(); it != msghandlers.end(); it++) {
00737         delete (*it).second;
00738     }
00739     for(HandlerMap::iterator it = updatehandlers.begin(); it != updatehandlers.end(); it++) {
00740         delete (*it).second;
00741     }
00742     msghandlers.clear();
00743     updatehandlers.clear();
00744 
00745     LOG("Vobject", 4, "excise: refcount on this is " << getCount());
00746     if(getCount() < 1) {
00747         LOG("Vobject", 0, "excise: refcount on this is " << getCount() << "!  The method which called excise() should be holding the last reference.  (I'm going to abort now).");
00748         abort();
00749     }
00750 }
00751 
00752 void VobjectImplementation::saveState(MessageBlock& output, set<string>& t, bool portable)
00753 {
00754     t = types;
00755 }
00756 
00757 void VobjectImplementation::addFlag(const string& flag)
00758 {
00759     flagstrings.insert(flag);
00760 }
00761 
00762 void VobjectImplementation::removeFlag(const string& flag)
00763 {
00764     flagstrings.erase(flag);
00765 }
00766 
00767 bool VobjectImplementation::checkFlag(const string& flag)
00768 {
00769     return (flagstrings.count(flag) > 0);
00770 }
00771 
00772 

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