WvStreams
|
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 }