WvStreams
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, wv::bind(&UniMountGen::gencallback, this,
00199                                      newgen->key, _1, _2));
00200 
00201     hold_delta();
00202     delta(key, WvString());
00203 
00204     makemount(key);
00205 
00206     if (gen && refresh)
00207         gen->refresh();
00208 
00209     mounts.prepend(newgen, true);
00210     
00211     delta(key, get(key));
00212     unhold_delta();
00213     if (!gen->exists("/"))
00214         gen->set("/", "");
00215     return gen;
00216 }
00217 
00218 
00219 void UniMountGen::unmount(IUniConfGen *gen, bool commit)
00220 {
00221     if (!gen)
00222         return;
00223     
00224     MountList::Iter i(mounts);
00225 
00226     for (i.rewind(); i.next() && i->gen != gen; )
00227         ;
00228 
00229     if (i->gen != gen)
00230         return;
00231 
00232     hold_delta();
00233     
00234     if (commit)
00235         gen->commit();
00236     gen->del_callback(this);
00237 
00238     UniConfKey key(i->key);
00239     IUniConfGen *next = NULL;
00240 
00241     delta(key, WvString());
00242 
00243     // Find the first generator mounted past the one we're removing (if
00244     // any). This way we can make sure that each generator still has keys
00245     // leading up to it (in case they lost their mountpoint due to the
00246     // unmounted generator)
00247     i.xunlink();
00248     if (i.next())
00249         next = i->gen;
00250 
00251     for (i.rewind(); i.next() && i->gen != next; )
00252     {
00253         if (key.suborsame(i->key) && key != i->key)
00254         {
00255             makemount(i->key);
00256             delta(i->key, get(i->key));
00257         }
00258     } 
00259 
00260     unhold_delta();
00261 }
00262 
00263 
00264 void UniMountGen::zap()
00265 {
00266     while (!mounts.isempty())
00267         unmount(mounts.first()->gen, false);
00268 }
00269 
00270 
00271 IUniConfGen *UniMountGen::whichmount(const UniConfKey &key,
00272                                     UniConfKey *mountpoint)
00273 {
00274     MountList::Iter i(mounts);
00275 
00276     for (i.rewind(); i.next(); )
00277     {
00278         if (i->key.suborsame(key))
00279         {
00280             if (mountpoint)
00281                 *mountpoint = i->key;
00282             return i->gen;
00283         }
00284     }
00285 
00286     return NULL;
00287 }
00288 
00289 
00290 bool UniMountGen::ismountpoint(const UniConfKey &key)
00291 {
00292     MountList::Iter i(mounts);
00293 
00294     for (i.rewind(); i.next(); )
00295     {
00296         if (i->key == key)
00297             return true;
00298     }
00299 
00300     return false;
00301 }
00302 
00303 static int wvstrcmp(const WvString *l, const WvString *r)
00304 {
00305     return strcmp(*l, *r);
00306 }
00307 
00308 UniMountGen::Iter *UniMountGen::iterator(const UniConfKey &key)
00309 {
00310     UniGenMount *found = findmount(key);
00311     if (found)
00312         return found->gen->iterator(trimkey(found->key, key));
00313     else
00314     {
00315         // deal with elements mounted on nothingness.
00316         // FIXME: this is really a hack, and should (somehow) be dealt with
00317         // in a more general way.
00318         ListIter *it = new ListIter(this);
00319 
00320         MountList::Iter i(mounts);
00321         WvStringTable t(10);
00322         for (i.rewind(); i.next(); )
00323         {
00324             if (key.numsegments() < i->key.numsegments()
00325               && key.suborsame(i->key))
00326             {
00327                 // trim off any stray segments coming between the virtual
00328                 // "key" we're iterating over and the mount
00329                 UniConfKey k1 = i->key.first(key.numsegments() + 1);
00330                 UniConfKey k2 = k1.last(); // final "key" should be size 1
00331 
00332                 if (!t[k2])
00333                     t.add(new WvString(k2), true);
00334             }
00335         }
00336         WvStringTable::Sorter s(t, &::wvstrcmp);
00337         for (s.rewind(); s.next();)
00338             it->add(*s);
00339 
00340         return it;
00341     }
00342 }
00343 
00344 
00345 // FIXME: this function will be rather slow if you try to iterate over multiple
00346 // generators and the latency level is high (as is the case with e.g.: the tcp generator). 
00347 // the fast path will only kick in if you iterate over a single generator.
00348 UniMountGen::Iter *UniMountGen::recursiveiterator(const UniConfKey &key)
00349 {
00350     UniGenMount *found = findmountunder(key);
00351     if (found)
00352         return found->gen->recursiveiterator(trimkey(found->key, key));
00353     else
00354         return UniConfGen::recursiveiterator(key);
00355 }
00356 
00357 
00358 UniMountGen::UniGenMount *UniMountGen::findmount(const UniConfKey &key)
00359 {
00360     // Find the needed generator and keep it as a lastfound
00361     MountList::Iter i(mounts);
00362     for (i.rewind(); i.next(); )
00363     {
00364         if (i->key.suborsame(key))
00365             return i.ptr();
00366     } 
00367 
00368     return NULL;
00369 }
00370 
00371 
00372 UniMountGen::UniGenMount *UniMountGen::findmountunder(const UniConfKey &key)
00373 {
00374     UniMountGen::UniGenMount * foundmount = NULL;
00375     int num_found_mounts = 0;
00376 
00377     // Find the needed generator and keep it as a lastfound
00378     MountList::Iter i(mounts);
00379     for (i.rewind(); i.next(); )
00380     {
00381         // key lies beneath mount (only care about the first)
00382         if (i->key.suborsame(key) && !foundmount)
00383         {
00384             foundmount = i.ptr();
00385             num_found_mounts++;
00386         }
00387         // mount lies beneath key
00388         else if (key.suborsame(i->key))
00389         {
00390             num_found_mounts++;
00391         }
00392     }
00393 
00394     if (num_found_mounts == 1 && foundmount)
00395         return foundmount;
00396 
00397     return NULL;
00398 }
00399 
00400 
00401 void UniMountGen::gencallback(const UniConfKey &base, const UniConfKey &key,
00402                               WvStringParm value)
00403 {
00404     delta(UniConfKey(base, key), value);
00405 }
00406 
00407 
00408 void UniMountGen::makemount(const UniConfKey &key)
00409 {
00410     // Create any keys needed leading up to the mount generator so that the
00411     // mountpoint exists
00412     UniConfKey::Iter i(key);
00413     UniConfKey points;
00414 
00415     for (i.rewind(); i.next(); )
00416     {
00417         points.append(*i);
00418         if (get(points).isnull())
00419             set(points, "");
00420     }
00421 
00422     // Set the mountpoint in the sub generator instead of on the generator
00423     // itself (since set will set it on the generator, instead of making the
00424     // mountpoint)
00425     UniGenMount *found = findmount(points.removelast());
00426     if (!found)
00427         return;
00428 
00429     if (found->gen->get(trimkey(found->key, key)).isnull())
00430         found->gen->set(trimkey(found->key, key), "");
00431 }