unimountgen.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * Defines a UniConfGen that manages a tree of UniConfGen instances.
00006  */
00007 #include "unimountgen.h"
00008 #include "wvmoniker.h"
00009 #include "wvhash.h"
00010 #include "wvstrutils.h"
00011 #include "unilistiter.h"
00012 #include "wvstringtable.h"
00013 #include <assert.h>
00014 
00015 /***** UniMountGen *****/
00016 
00017 UniMountGen::UniMountGen()
00018 {
00019     // nothing special
00020 }
00021 
00022 
00023 UniMountGen::~UniMountGen()
00024 {
00025     zap();
00026 }
00027 
00028 
00029 WvString UniMountGen::get(const UniConfKey &key)
00030 {
00031     UniGenMount *found = findmount(key);
00032     if (!found)
00033     {
00034         // if there are keys that _do_ have a mount under this one,
00035         // then we consider it to exist (as a key with a blank value)
00036         if (has_subkey(key, NULL))
00037             return "";
00038 
00039         return WvString::null;
00040     }
00041 
00042     return found->gen->get(trimkey(found->key, key));
00043 }
00044 
00045 
00046 void UniMountGen::set(const UniConfKey &key, WvStringParm value)
00047 {
00048     UniGenMount *found = findmount(key);
00049     if (!found)
00050         return;
00051     found->gen->set(trimkey(found->key, key), value);
00052 }
00053 
00054 
00055 struct UniMountGen::UniGenMountPairs
00056 {
00057     UniGenMount *mount;
00058     WvString key;
00059     UniConfPairList pairs;
00060 
00061     UniGenMountPairs(UniGenMount *_mount)
00062         : mount(_mount)
00063     {
00064         if (mount)
00065             key = mount->key;
00066     }
00067 };
00068 
00069 
00070 void UniMountGen::setv(const UniConfPairList &pairs)
00071 {
00072     UniGenMountPairsDict mountpairs(mounts.count());
00073 
00074     {
00075         MountList::Iter m(mounts);
00076         for (m.rewind(); m.next(); )
00077             mountpairs.add(new UniGenMountPairs(m.ptr()), true);
00078     }
00079 
00080     {
00081         UniConfPairList::Iter pair(pairs);
00082         for (pair.rewind(); pair.next(); )
00083         {
00084             UniGenMount *found = findmount(pair->key());
00085             if (!found)
00086                 continue;
00087             UniConfPair *trimmed = new UniConfPair(trimkey(found->key,
00088                                                            pair->key()),
00089                                                    pair->value());
00090             mountpairs[found->key]->pairs.add(trimmed, true);
00091         }
00092     }
00093 
00094     UniGenMountPairsDict::Iter i(mountpairs);
00095     for (i.rewind(); i.next(); )
00096         i->mount->gen->setv(i->pairs);
00097 }
00098 
00099 
00100 bool UniMountGen::exists(const UniConfKey &key)
00101 {
00102     UniGenMount *found = findmount(key);
00103     //fprintf(stdout, "unimountgen:exists:found %p\n", found);
00104     if (found && found->gen->exists(trimkey(found->key, key)))
00105         return true;
00106     else
00107         //if there's something mounted and set on a subkey, this key must 
00108         //*exist* along the way
00109         return has_subkey(key, found);
00110 }
00111 
00112 
00113 bool UniMountGen::haschildren(const UniConfKey &key)
00114 {
00115     UniGenMount *found = findmount(key);
00116 //    fprintf(stdout, "haschildren:found %p\n", found);
00117     if (found && found->gen->haschildren(trimkey(found->key, key)))
00118         return true;
00119 
00120     // if we get here, the generator we used didn't have a subkey.  We want
00121     // to see if there's anyone mounted at a subkey of the requested key; if
00122     // so, then we definitely have a subkey.
00123     return has_subkey(key, found);
00124 }
00125 
00126 
00127 bool UniMountGen::has_subkey(const UniConfKey &key, UniGenMount *found)
00128 {
00129     MountList::Iter i(mounts);
00130     for (i.rewind(); i.next(); )
00131     {
00132         if (key.suborsame(i->key) && key < i->key)
00133         {
00134             //fprintf(stdout, "%s has_subkey %s : true\n", key.printable().cstr(), 
00135             //        i->key.printable().cstr());            
00136             return true;
00137         }
00138 
00139         // the list is sorted innermost-first.  So if we find the key
00140         // we started with, we've finished searching all children of it.
00141         if (found && (i->gen == found->gen))
00142             break;
00143     }
00144 
00145     //fprintf(stdout, "%s has_subkey false \n", key.printable().cstr());
00146     return false;
00147 }
00148 
00149 bool UniMountGen::refresh()
00150 {
00151     hold_delta();
00152 
00153     bool result = true;
00154 
00155     MountList::Iter i(mounts);
00156     for (i.rewind(); i.next(); )
00157         result = result && i->gen->refresh();
00158 
00159     unhold_delta();
00160     return result;
00161 }
00162 
00163 
00164 void UniMountGen::commit()
00165 {
00166     hold_delta();
00167 
00168     MountList::Iter i(mounts);
00169     for (i.rewind(); i.next();)
00170         i->gen->commit();
00171 
00172     unhold_delta();
00173 }
00174 
00175 
00176 IUniConfGen *UniMountGen::mount(const UniConfKey &key,
00177                                WvStringParm moniker, bool refresh)
00178 {
00179     IUniConfGen *gen = wvcreate<IUniConfGen>(moniker);
00180     if (gen)
00181         mountgen(key, gen, refresh); // assume always succeeds for now
00182 #if DEBUG
00183     assert(gen && "Moniker doesn't get us a generator!");
00184 #endif
00185     if (gen && !gen->exists("/"))
00186         gen->set("/", "");
00187     return gen;
00188 }
00189 
00190 
00191 IUniConfGen *UniMountGen::mountgen(const UniConfKey &key,
00192                                    IUniConfGen *gen, bool refresh)
00193 {
00194     if (!gen)
00195         return NULL;
00196     
00197     UniGenMount *newgen = new UniGenMount(gen, key);
00198     gen->add_callback(this,
00199                       WvBoundCallback<UniConfGenCallback, const UniConfKey&>
00200                       (this, &UniMountGen::gencallback, newgen->key));
00201 
00202     hold_delta();
00203     delta(key, WvString());
00204 
00205     makemount(key);
00206 
00207     if (gen && refresh)
00208         gen->refresh();
00209 
00210     mounts.prepend(newgen, true);
00211     
00212     delta(key, get(key));
00213     unhold_delta();
00214     if (!gen->exists("/"))
00215         gen->set("/", "");
00216     return gen;
00217 }
00218 
00219 
00220 void UniMountGen::unmount(IUniConfGen *gen, bool commit)
00221 {
00222     if (!gen)
00223         return;
00224     
00225     MountList::Iter i(mounts);
00226 
00227     for (i.rewind(); i.next() && i->gen != gen; )
00228         ;
00229 
00230     if (i->gen != gen)
00231         return;
00232 
00233     hold_delta();
00234     
00235     if (commit)
00236         gen->commit();
00237     gen->del_callback(this);
00238 
00239     UniConfKey key(i->key);
00240     IUniConfGen *next = NULL;
00241 
00242     delta(key, WvString());
00243 
00244     // Find the first generator mounted past the one we're removing (if
00245     // any). This way we can make sure that each generator still has keys
00246     // leading up to it (in case they lost their mountpoint due to the
00247     // unmounted generator)
00248     i.xunlink();
00249     if (i.next())
00250         next = i->gen;
00251 
00252     for (i.rewind(); i.next() && i->gen != next; )
00253     {
00254         if (key.suborsame(i->key) && key != i->key)
00255         {
00256             makemount(i->key);
00257             delta(i->key, get(i->key));
00258         }
00259     } 
00260 
00261     unhold_delta();
00262 }
00263 
00264 
00265 void UniMountGen::zap()
00266 {
00267     while (!mounts.isempty())
00268         unmount(mounts.first()->gen, false);
00269 }
00270 
00271 
00272 IUniConfGen *UniMountGen::whichmount(const UniConfKey &key,
00273                                     UniConfKey *mountpoint)
00274 {
00275     MountList::Iter i(mounts);
00276 
00277     for (i.rewind(); i.next(); )
00278     {
00279         if (i->key.suborsame(key))
00280         {
00281             if (mountpoint)
00282                 *mountpoint = i->key;
00283             return i->gen;
00284         }
00285     }
00286 
00287     return NULL;
00288 }
00289 
00290 
00291 bool UniMountGen::ismountpoint(const UniConfKey &key)
00292 {
00293     MountList::Iter i(mounts);
00294 
00295     for (i.rewind(); i.next(); )
00296     {
00297         if (i->key == key)
00298             return true;
00299     }
00300 
00301     return false;
00302 }
00303 
00304 static int wvstrcmp(const WvString *l, const WvString *r)
00305 {
00306     return strcmp(*l, *r);
00307 }
00308 
00309 UniMountGen::Iter *UniMountGen::iterator(const UniConfKey &key)
00310 {
00311     UniGenMount *found = findmount(key);
00312     if (found)
00313         return found->gen->iterator(trimkey(found->key, key));
00314     else
00315     {
00316         // deal with elements mounted on nothingness.
00317         // FIXME: this is really a hack, and should (somehow) be dealt with
00318         // in a more general way.
00319         ListIter *it = new ListIter(this);
00320 
00321         MountList::Iter i(mounts);
00322         WvStringTable t(10);
00323         for (i.rewind(); i.next(); )
00324         {
00325             if (key.numsegments() < i->key.numsegments()
00326               && key.suborsame(i->key))
00327             {
00328                 // trim off any stray segments coming between the virtual
00329                 // "key" we're iterating over and the mount
00330                 UniConfKey k1 = i->key.first(key.numsegments() + 1);
00331                 UniConfKey k2 = k1.last(); // final "key" should be size 1
00332 
00333                 if (!t[k2])
00334                     t.add(new WvString(k2), true);
00335             }
00336         }
00337         WvStringTable::Sorter s(t, &::wvstrcmp);
00338         for (s.rewind(); s.next();)
00339             it->add(*s);
00340 
00341         return it;
00342     }
00343 }
00344 
00345 
00346 // FIXME: this function will be rather slow if you try to iterate over multiple
00347 // generators and the latency level is high (as is the case with e.g.: the tcp generator). 
00348 // the fast path will only kick in if you iterate over a single generator.
00349 UniMountGen::Iter *UniMountGen::recursiveiterator(const UniConfKey &key)
00350 {
00351     UniGenMount *found = findmountunder(key);
00352     if (found)
00353         return found->gen->recursiveiterator(trimkey(found->key, key));
00354     else
00355         return UniConfGen::recursiveiterator(key);
00356 }
00357 
00358 
00359 UniMountGen::UniGenMount *UniMountGen::findmount(const UniConfKey &key)
00360 {
00361     // Find the needed generator and keep it as a lastfound
00362     MountList::Iter i(mounts);
00363     for (i.rewind(); i.next(); )
00364     {
00365         if (i->key.suborsame(key))
00366             return i.ptr();
00367     } 
00368 
00369     return NULL;
00370 }
00371 
00372 
00373 UniMountGen::UniGenMount *UniMountGen::findmountunder(const UniConfKey &key)
00374 {
00375     UniMountGen::UniGenMount * foundmount = NULL;
00376     int num_found_mounts = 0;
00377 
00378     // Find the needed generator and keep it as a lastfound
00379     MountList::Iter i(mounts);
00380     for (i.rewind(); i.next(); )
00381     {
00382         // key lies beneath mount (only care about the first)
00383         if (i->key.suborsame(key) && !foundmount)
00384         {
00385             foundmount = i.ptr();
00386             num_found_mounts++;
00387         }
00388         // mount lies beneath key
00389         else if (key.suborsame(i->key))
00390         {
00391             num_found_mounts++;
00392         }
00393     }
00394 
00395     if (num_found_mounts == 1 && foundmount)
00396         return foundmount;
00397 
00398     return NULL;
00399 }
00400 
00401 
00402 void UniMountGen::gencallback(const UniConfKey &base, const UniConfKey &key,
00403                               WvStringParm value)
00404 {
00405     delta(UniConfKey(base, key), value);
00406 }
00407 
00408 
00409 void UniMountGen::makemount(const UniConfKey &key)
00410 {
00411     // Create any keys needed leading up to the mount generator so that the
00412     // mountpoint exists
00413     UniConfKey::Iter i(key);
00414     UniConfKey points;
00415 
00416     for (i.rewind(); i.next(); )
00417     {
00418         points.append(*i);
00419         if (get(points).isnull())
00420             set(points, "");
00421     }
00422 
00423     // Set the mountpoint in the sub generator instead of on the generator
00424     // itself (since set will set it on the generator, instead of making the
00425     // mountpoint)
00426     UniGenMount *found = findmount(points.removelast());
00427     if (!found)
00428         return;
00429 
00430     if (found->gen->get(trimkey(found->key, key)).isnull())
00431         found->gen->set(trimkey(found->key, key), "");
00432 }

Generated on Thu Jan 24 16:50:55 2008 for WvStreams by  doxygen 1.5.4