WvStreams
unimountgen.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Defines a UniConfGen that manages a tree of UniConfGen instances.
6 */
7#include "unimountgen.h"
8#include "wvmoniker.h"
9#include "wvhash.h"
10#include "wvstrutils.h"
11#include "unilistiter.h"
12#include "wvstringtable.h"
13#include <assert.h>
14
15/***** UniMountGen *****/
16
18{
19 // nothing special
20}
21
22
24{
25 zap();
26}
27
28
30{
31 UniGenMount *found = findmount(key);
32 if (!found)
33 {
34 // if there are keys that _do_ have a mount under this one,
35 // then we consider it to exist (as a key with a blank value)
36 if (has_subkey(key, NULL))
37 return "";
38
39 return WvString::null;
40 }
41
42 return found->gen->get(trimkey(found->key, key));
43}
44
45
47{
48 UniGenMount *found = findmount(key);
49 if (!found)
50 return;
51 found->gen->set(trimkey(found->key, key), value);
52}
53
54
56{
57 UniGenMount *mount;
58 WvString key;
59 UniConfPairList pairs;
60
62 : mount(_mount)
63 {
64 if (mount)
65 key = mount->key;
66 }
67};
68
69
70void UniMountGen::setv(const UniConfPairList &pairs)
71{
72 UniGenMountPairsDict mountpairs(mounts.count());
73
74 {
75 MountList::Iter m(mounts);
76 for (m.rewind(); m.next(); )
77 mountpairs.add(new UniGenMountPairs(m.ptr()), true);
78 }
79
80 {
81 UniConfPairList::Iter pair(pairs);
82 for (pair.rewind(); pair.next(); )
83 {
84 UniGenMount *found = findmount(pair->key());
85 if (!found)
86 continue;
87 UniConfPair *trimmed = new UniConfPair(trimkey(found->key,
88 pair->key()),
89 pair->value());
90 mountpairs[found->key]->pairs.add(trimmed, true);
91 }
92 }
93
94 UniGenMountPairsDict::Iter i(mountpairs);
95 for (i.rewind(); i.next(); )
96 i->mount->gen->setv(i->pairs);
97}
98
99
101{
102 UniGenMount *found = findmount(key);
103 //fprintf(stdout, "unimountgen:exists:found %p\n", found);
104 if (found && found->gen->exists(trimkey(found->key, key)))
105 return true;
106 else
107 //if there's something mounted and set on a subkey, this key must
108 //*exist* along the way
109 return has_subkey(key, found);
110}
111
112
114{
115 UniGenMount *found = findmount(key);
116// fprintf(stdout, "haschildren:found %p\n", found);
117 if (found && found->gen->haschildren(trimkey(found->key, key)))
118 return true;
119
120 // if we get here, the generator we used didn't have a subkey. We want
121 // to see if there's anyone mounted at a subkey of the requested key; if
122 // so, then we definitely have a subkey.
123 return has_subkey(key, found);
124}
125
126
127bool UniMountGen::has_subkey(const UniConfKey &key, UniGenMount *found)
128{
129 MountList::Iter i(mounts);
130 for (i.rewind(); i.next(); )
131 {
132 if (key.suborsame(i->key) && key < i->key)
133 {
134 //fprintf(stdout, "%s has_subkey %s : true\n", key.printable().cstr(),
135 // i->key.printable().cstr());
136 return true;
137 }
138
139 // the list is sorted innermost-first. So if we find the key
140 // we started with, we've finished searching all children of it.
141 if (found && (i->gen == found->gen))
142 break;
143 }
144
145 //fprintf(stdout, "%s has_subkey false \n", key.printable().cstr());
146 return false;
147}
148
150{
151 hold_delta();
152
153 bool result = true;
154
155 MountList::Iter i(mounts);
156 for (i.rewind(); i.next(); )
157 result = result && i->gen->refresh();
158
159 unhold_delta();
160 return result;
161}
162
163
165{
166 hold_delta();
167
168 MountList::Iter i(mounts);
169 for (i.rewind(); i.next();)
170 i->gen->commit();
171
172 unhold_delta();
173}
174
175
177 WvStringParm moniker, bool refresh)
178{
179 IUniConfGen *gen = wvcreate<IUniConfGen>(moniker);
180 if (gen)
181 mountgen(key, gen, refresh); // assume always succeeds for now
182#if DEBUG
183 assert(gen && "Moniker doesn't get us a generator!");
184#endif
185 if (gen && !gen->exists("/"))
186 gen->set("/", "");
187 return gen;
188}
189
190
192 IUniConfGen *gen, bool refresh)
193{
194 if (!gen)
195 return NULL;
196
197 UniGenMount *newgen = new UniGenMount(gen, key);
198 gen->add_callback(this, wv::bind(&UniMountGen::gencallback, this,
199 newgen->key, _1, _2));
200
201 hold_delta();
202 delta(key, WvString());
203
204 makemount(key);
205
206 if (gen && refresh)
207 gen->refresh();
208
209 mounts.prepend(newgen, true);
210
211 delta(key, get(key));
212 unhold_delta();
213 if (!gen->exists("/"))
214 gen->set("/", "");
215 return gen;
216}
217
218
219void UniMountGen::unmount(IUniConfGen *gen, bool commit)
220{
221 if (!gen)
222 return;
223
224 MountList::Iter i(mounts);
225
226 for (i.rewind(); i.next() && i->gen != gen; )
227 ;
228
229 if (i->gen != gen)
230 return;
231
232 hold_delta();
233
234 if (commit)
235 gen->commit();
236 gen->del_callback(this);
237
238 UniConfKey key(i->key);
239 IUniConfGen *next = NULL;
240
241 delta(key, WvString());
242
243 // Find the first generator mounted past the one we're removing (if
244 // any). This way we can make sure that each generator still has keys
245 // leading up to it (in case they lost their mountpoint due to the
246 // unmounted generator)
247 i.xunlink();
248 if (i.next())
249 next = i->gen;
250
251 for (i.rewind(); i.next() && i->gen != next; )
252 {
253 if (key.suborsame(i->key) && key != i->key)
254 {
255 makemount(i->key);
256 delta(i->key, get(i->key));
257 }
258 }
259
260 unhold_delta();
261}
262
263
264void UniMountGen::zap()
265{
266 while (!mounts.isempty())
267 unmount(mounts.first()->gen, false);
268}
269
270
272 UniConfKey *mountpoint)
273{
274 MountList::Iter i(mounts);
275
276 for (i.rewind(); i.next(); )
277 {
278 if (i->key.suborsame(key))
279 {
280 if (mountpoint)
281 *mountpoint = i->key;
282 return i->gen;
283 }
284 }
285
286 return NULL;
287}
288
289
291{
292 MountList::Iter i(mounts);
293
294 for (i.rewind(); i.next(); )
295 {
296 if (i->key == key)
297 return true;
298 }
299
300 return false;
301}
302
303static int wvstrcmp(const WvString *l, const WvString *r)
304{
305 return strcmp(*l, *r);
306}
307
309{
310 UniGenMount *found = findmount(key);
311 if (found)
312 return found->gen->iterator(trimkey(found->key, key));
313 else
314 {
315 // deal with elements mounted on nothingness.
316 // FIXME: this is really a hack, and should (somehow) be dealt with
317 // in a more general way.
318 ListIter *it = new ListIter(this);
319
320 MountList::Iter i(mounts);
321 WvStringTable t(10);
322 for (i.rewind(); i.next(); )
323 {
324 if (key.numsegments() < i->key.numsegments()
325 && key.suborsame(i->key))
326 {
327 // trim off any stray segments coming between the virtual
328 // "key" we're iterating over and the mount
329 UniConfKey k1 = i->key.first(key.numsegments() + 1);
330 UniConfKey k2 = k1.last(); // final "key" should be size 1
331
332 if (!t[k2])
333 t.add(new WvString(k2), true);
334 }
335 }
336 WvStringTable::Sorter s(t, &::wvstrcmp);
337 for (s.rewind(); s.next();)
338 it->add(*s);
339
340 return it;
341 }
342}
343
344
345// FIXME: this function will be rather slow if you try to iterate over multiple
346// generators and the latency level is high (as is the case with e.g.: the tcp generator).
347// the fast path will only kick in if you iterate over a single generator.
349{
350 UniGenMount *found = findmountunder(key);
351 if (found)
352 return found->gen->recursiveiterator(trimkey(found->key, key));
353 else
355}
356
357
358UniMountGen::UniGenMount *UniMountGen::findmount(const UniConfKey &key)
359{
360 // Find the needed generator and keep it as a lastfound
361 MountList::Iter i(mounts);
362 for (i.rewind(); i.next(); )
363 {
364 if (i->key.suborsame(key))
365 return i.ptr();
366 }
367
368 return NULL;
369}
370
371
372UniMountGen::UniGenMount *UniMountGen::findmountunder(const UniConfKey &key)
373{
374 UniMountGen::UniGenMount * foundmount = NULL;
375 int num_found_mounts = 0;
376
377 // Find the needed generator and keep it as a lastfound
378 MountList::Iter i(mounts);
379 for (i.rewind(); i.next(); )
380 {
381 // key lies beneath mount (only care about the first)
382 if (i->key.suborsame(key) && !foundmount)
383 {
384 foundmount = i.ptr();
385 num_found_mounts++;
386 }
387 // mount lies beneath key
388 else if (key.suborsame(i->key))
389 {
390 num_found_mounts++;
391 }
392 }
393
394 if (num_found_mounts == 1 && foundmount)
395 return foundmount;
396
397 return NULL;
398}
399
400
401void UniMountGen::gencallback(const UniConfKey &base, const UniConfKey &key,
402 WvStringParm value)
403{
404 delta(UniConfKey(base, key), value);
405}
406
407
408void UniMountGen::makemount(const UniConfKey &key)
409{
410 // Create any keys needed leading up to the mount generator so that the
411 // mountpoint exists
412 UniConfKey::Iter i(key);
413 UniConfKey points;
414
415 for (i.rewind(); i.next(); )
416 {
417 points.append(*i);
418 if (get(points).isnull())
419 set(points, "");
420 }
421
422 // Set the mountpoint in the sub generator instead of on the generator
423 // itself (since set will set it on the generator, instead of making the
424 // mountpoint)
425 UniGenMount *found = findmount(points.removelast());
426 if (!found)
427 return;
428
429 if (found->gen->get(trimkey(found->key, key)).isnull())
430 found->gen->set(trimkey(found->key, key), "");
431}
An abstract data container that backs a UniConf tree.
Definition uniconfgen.h:40
virtual bool exists(const UniConfKey &key)=0
Without fetching its value, returns true if a key exists.
virtual bool refresh()=0
Refreshes information about a key recursively.
::UniListIter ListIter
An iterator over a constant list of keys (see below)
Definition uniconfgen.h:163
virtual void add_callback(void *cookie, const UniConfGenCallback &callback)=0
Adds a callback for change notification.
virtual void commit()=0
Commits any changes.
virtual void del_callback(void *cookie)=0
Removes a callback for change notification.
virtual void set(const UniConfKey &key, WvStringParm value)=0
Stores a string value for a key into the registry.
An abstract iterator over keys and values in a generator.
Definition uniconfgen.h:324
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition uniconfgen.cc:32
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition uniconfgen.cc:38
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition uniconfgen.cc:77
virtual Iter * recursiveiterator(const UniConfKey &key)
Like iterator(), but the returned iterator is recursive, that is, it will return children of the imme...
An iterator over the segments of a key.
Definition uniconfkey.h:464
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition uniconfkey.h:39
UniConfKey removelast(int n=1) const
Returns the path formed by removing the last n segments of this path.
Definition uniconfkey.h:346
int numsegments() const
Returns the number of segments in this path.
Definition uniconfkey.h:287
void append(const UniConfKey &other)
Appends a path to this path.
UniConfKey first(int n=1) const
Returns the path formed by the n first segments of this path.
Definition uniconfkey.h:314
bool suborsame(const UniConfKey &key) const
Returns true if 'key' is a the same, or a subkey, of this UniConfKey.
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition uniconfkey.h:324
Represents a simple key-value pair.
Definition uniconfpair.h:17
An iterator that iterates through a constant list of keys.
Definition unilistiter.h:28
void add(const UniConfKey &k, WvStringParm v=WvString::null)
Add a key/value pair to the list that gets returned by this iterator.
virtual void commit()
Commits any changes.
virtual IUniConfGen * whichmount(const UniConfKey &key, UniConfKey *mountpoint)
Finds the generator that owns a key.
virtual IUniConfGen * mountgen(const UniConfKey &key, IUniConfGen *gen, bool refresh)
Mounts a generator at a key.
virtual Iter * recursiveiterator(const UniConfKey &key)
Like iterator(), but the returned iterator is recursive, that is, it will return children of the imme...
virtual bool ismountpoint(const UniConfKey &key)
Determines if a key is a mountpoint.
virtual bool refresh()
Refreshes information about a key recursively.
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
UniMountGen()
Creates an empty UniConf tree with no mounted stores.
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
virtual IUniConfGen * mount(const UniConfKey &key, WvStringParm moniker, bool refresh)
Mounts a generator at a key using a moniker.
virtual ~UniMountGen()
Destroys the UniConf tree along with all uncommitted data.
virtual bool haschildren(const UniConfKey &key)
Returns true if a key has children.
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
virtual bool exists(const UniConfKey &key)
Without fetching its value, returns true if a key exists.
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
virtual void unmount(IUniConfGen *gen, bool commit)
Unmounts the generator at a key and releases it.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition wvstring.h:94
bool isnull() const
returns true if this string is null
Definition wvstring.h:290
WvString is an implementation of a simple and efficient printable-string class.
Definition wvstring.h:330
Various little string functions.