00001 #include "unitransactiongen.h"
00002 #include "uniconftree.h"
00003 #include "unilistiter.h"
00004 #include "wvmoniker.h"
00005
00006 static IUniConfGen *creator(WvStringParm s)
00007 {
00008 IUniConfGen *base = wvcreate<IUniConfGen>(s);
00009 if (base)
00010 return new UniTransactionGen(base);
00011 else
00012 return NULL;
00013 }
00014
00015 static WvMoniker<IUniConfGen> moniker("transaction", creator);
00016
00017
00018
00019 enum changeMode
00020 {
00021
00022
00023
00024
00025 NEWVALUE,
00026
00027
00028
00029
00030 NEWTREE,
00031
00032
00033
00034
00035
00036
00037
00038
00039 NEWNODE,
00040
00041
00042
00043
00044 BLANK
00045 };
00046
00047 class UniConfChangeTree : public UniConfTree<UniConfChangeTree>
00048 {
00049 public:
00050 changeMode mode;
00051
00052
00053
00054
00055
00056 WvString newvalue;
00057 UniConfValueTree *newtree;
00058 bool was_null_or_empty;
00059
00060
00061 UniConfChangeTree(UniConfChangeTree *parent, const UniConfKey &key)
00062 : UniConfTree<UniConfChangeTree>(parent, key), newtree(0) {}
00063
00064
00065 ~UniConfChangeTree()
00066 {
00067 if (newtree)
00068 delete newtree;
00069 }
00070 };
00071
00072
00073
00074 class GenStyleValueTreeIter : public UniConfGen::Iter
00075 {
00076 public:
00077 GenStyleValueTreeIter(UniConfValueTree *node)
00078 : i(*node)
00079 {
00080
00081 }
00082
00083 ~GenStyleValueTreeIter()
00084 {
00085
00086 }
00087
00088 void rewind() { i.rewind(); }
00089 bool next() { return i.next(); }
00090 UniConfKey key() const { return i->key(); }
00091 WvString value() const { return i->value(); }
00092
00093 private:
00094 UniConfValueTree::Iter i;
00095 };
00096
00097
00098
00099
00100
00101
00102 class GenStyleChangeTreeIter : public UniConfGen::Iter
00103 {
00104 public:
00105 GenStyleChangeTreeIter(UniConfChangeTree *_root,
00106 const UniConfKey &_section,
00107 IUniConfGen *_base)
00108 : root(_root), section(_section), base(_base),
00109 doing_i1(true), i1(*root), i2(base->iterator(section))
00110 {
00111
00112 }
00113
00114 ~GenStyleChangeTreeIter()
00115 {
00116
00117 if (i2) delete i2;
00118 }
00119
00120 void rewind()
00121 {
00122 i1.rewind();
00123 doing_i1 = true;
00124 }
00125
00126 bool next()
00127 {
00128 if (doing_i1)
00129 {
00130 for (;;)
00131 {
00132 if (i1.next())
00133 {
00134 if (i1->mode == NEWVALUE ||
00135 i1->mode == NEWNODE ||
00136 (i1->mode == NEWTREE && i1->newtree))
00137 return true;
00138 }
00139 else
00140 break;
00141 }
00142 doing_i1 = false;
00143 if (i2) i2->rewind();
00144 }
00145 if (i2)
00146 {
00147 for (;;)
00148 {
00149 if (i2->next())
00150 {
00151 UniConfChangeTree *node = root->findchild(i2->key());
00152 if (!node || node->mode == BLANK)
00153 return true;
00154 }
00155 else
00156 break;
00157 }
00158 }
00159 return false;
00160 }
00161
00162 UniConfKey key() const
00163 {
00164 if (doing_i1)
00165 return i1->key();
00166 else if (i2)
00167 return i2->key();
00168 else
00169 return UniConfKey();
00170 }
00171
00172 WvString value() const
00173 {
00174 if (doing_i1)
00175 {
00176 if (i1->mode == NEWVALUE)
00177 return i1->newvalue;
00178 else if (i1->mode == NEWTREE)
00179 return i1->newtree->value();
00180 else
00181 {
00182 WvString value(base->get(UniConfKey(section, i1->key())));
00183 return !value ? WvString::empty : value;
00184 }
00185 }
00186 else
00187 {
00188 return i2->value();
00189 }
00190 }
00191
00192 private:
00193 UniConfChangeTree *root;
00194 UniConfKey section;
00195 IUniConfGen *base;
00196
00197 bool doing_i1;
00198 UniConfChangeTree::Iter i1;
00199 UniConfGen::Iter *i2;
00200 };
00201
00202 UniTransactionGen::UniTransactionGen(IUniConfGen *_base)
00203 : root(NULL), base(_base)
00204 {
00205 base->add_callback(this,
00206 UniConfGenCallback(this, &UniTransactionGen::gencallback));
00207 }
00208
00209 UniTransactionGen::~UniTransactionGen()
00210 {
00211 base->del_callback(this);
00212 WVRELEASE(base);
00213 if (root)
00214 delete root;
00215 }
00216
00217 WvString UniTransactionGen::get(const UniConfKey &key)
00218 {
00219 UniConfChangeTree *node = root;
00220 for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00221 {
00222 if (!node)
00223
00224
00225
00226 return base->get(key);
00227 else if (node->mode == NEWTREE)
00228 {
00229
00230
00231
00232 if (node->newtree)
00233 {
00234 UniConfValueTree *subnode = node->newtree->find(
00235 key.last(key.numsegments() - seg));
00236 if (subnode)
00237 return subnode->value();
00238 }
00239 return WvString::null;
00240 }
00241 else if (seg == key.numsegments())
00242 {
00243
00244
00245
00246 if (node->mode == NEWVALUE)
00247 return node->newvalue;
00248 WvString value(base->get(key.first(seg)));
00249 return (node->mode == NEWNODE && !value) ? WvString::empty : value;
00250 }
00251 }
00252 }
00253
00254 void UniTransactionGen::set(const UniConfKey &key, WvStringParm value)
00255 {
00256 hold_delta();
00257 root = set_change(root, key, 0, value);
00258 unhold_delta();
00259 }
00260
00261 void UniTransactionGen::setv(const UniConfPairList &pairs)
00262 {
00263 hold_delta();
00264 UniConfPairList::Iter i(pairs);
00265 for (i.rewind(); i.next(); )
00266 root = set_change(root, i->key(), 0, i->value());
00267 unhold_delta();
00268 }
00269
00270 void UniTransactionGen::commit()
00271 {
00272 if (root)
00273 {
00274
00275
00276
00277 hold_delta();
00278 apply_changes(root, UniConfKey());
00279
00280
00281 base->commit();
00282
00283
00284
00285 delete root;
00286 root = NULL;
00287 unhold_delta();
00288 }
00289
00290
00291 }
00292
00293 bool UniTransactionGen::refresh()
00294 {
00295 if (root)
00296 {
00297 hold_delta();
00298 cancel_changes(root, UniConfKey());
00299 delete root;
00300 root = NULL;
00301 unhold_delta();
00302
00303
00304
00305 }
00306
00307
00308 return base->refresh();
00309 }
00310
00311 UniConfGen::Iter *UniTransactionGen::iterator(const UniConfKey &key)
00312 {
00313 UniConfChangeTree *node = root;
00314 for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00315 {
00316 if (!node)
00317
00318
00319
00320 return base->iterator(key);
00321 else if (node->mode == NEWTREE)
00322 {
00323
00324
00325
00326 if (node->newtree)
00327 {
00328 UniConfValueTree *subnode = node->newtree->find(
00329 key.last(key.numsegments() - seg));
00330 if (subnode)
00331 {
00332 UniConfGen::Iter *i = new GenStyleValueTreeIter(subnode);
00333 UniListIter *i2 = new UniListIter(this);
00334 i2->autofill(i);
00335 delete i;
00336 return i2;
00337 }
00338 }
00339 return new UniConfGen::NullIter();
00340 }
00341 else if (seg == key.numsegments())
00342 {
00343
00344
00345 UniConfGen::Iter *i = new GenStyleChangeTreeIter(node, key, base);
00346 UniListIter *i2 = new UniListIter(this);
00347 i2->autofill(i);
00348 delete i;
00349 return i2;
00350 }
00351 }
00352 }
00353
00354 void UniTransactionGen::apply_values(UniConfValueTree *newcontents,
00355 const UniConfKey §ion)
00356 {
00357 base->set(section, newcontents->value());
00358
00359 UniConfGen::Iter *j = base->iterator(section);
00360 if (j)
00361 {
00362 for (j->rewind(); j->next();)
00363 {
00364 if (newcontents->findchild(j->key()) == NULL)
00365
00366
00367
00368 base->set(UniConfKey(section, j->key()), WvString::null);
00369 }
00370 delete j;
00371 }
00372
00373
00374 UniConfValueTree::Iter i(*newcontents);
00375 for (i.rewind(); i.next();)
00376 apply_values(i.ptr(), UniConfKey(section, i->key()));
00377 }
00378
00379 void UniTransactionGen::apply_changes(UniConfChangeTree *node,
00380 const UniConfKey §ion)
00381 {
00382 if (node->mode == NEWTREE)
00383 {
00384
00385
00386 if (node->newtree == NULL)
00387 base->set(section, WvString::null);
00388 else
00389 apply_values(node->newtree, section);
00390
00391 return;
00392 }
00393 else if (node->mode == NEWVALUE)
00394 {
00395
00396 base->set(section, node->newvalue);
00397 }
00398 else if (node->mode == NEWNODE)
00399 {
00400
00401 if (!base->exists(section))
00402
00403
00404 base->set(section, WvString::empty);
00405
00406
00407
00408 }
00409
00410
00411 UniConfChangeTree::Iter i(*node);
00412 for (i.rewind(); i.next();)
00413 apply_changes(i.ptr(), UniConfKey(section, i->key()));
00414 }
00415
00416 struct my_userdata
00417 {
00418 UniConfValueTree *node;
00419 const UniConfKey &key;
00420 };
00421
00422 void UniTransactionGen::deletion_visitor(const UniConfValueTree *node,
00423 void *userdata)
00424 {
00425 my_userdata *data = (my_userdata *)userdata;
00426 delta(UniConfKey(data->key, node->fullkey(data->node)), WvString::null);
00427 }
00428
00429
00430
00431 void UniTransactionGen::cancel_values(UniConfValueTree *newcontents,
00432 const UniConfKey §ion)
00433 {
00434 WvString value(base->get(section));
00435 if (!newcontents || newcontents->value() != value)
00436 delta(section, value);
00437
00438 if (newcontents)
00439 {
00440 UniConfValueTree::Iter i(*newcontents);
00441 for (i.rewind(); i.next();)
00442 {
00443 UniConfKey subkey(section, i->key());
00444 if (!base->exists(subkey))
00445 {
00446 my_userdata data = { i.ptr(), subkey };
00447 i->visit(
00448 UniConfValueTree::Visitor(
00449 this, &UniTransactionGen::deletion_visitor),
00450 (void *)&data, false, true);
00451 }
00452 }
00453 }
00454
00455 UniConfGen::Iter *i = base->iterator(section);
00456 if (i)
00457 {
00458 for (i->rewind(); i->next();)
00459 cancel_values(newcontents ?
00460 newcontents->findchild(i->key()) : NULL,
00461 UniConfKey(section, i->key()));
00462 delete i;
00463 }
00464 }
00465
00466
00467
00468 void UniTransactionGen::cancel_changes(UniConfChangeTree *node,
00469 const UniConfKey §ion)
00470 {
00471 if (node->mode == NEWTREE)
00472 {
00473 if (!base->exists(section))
00474 {
00475 if (node->newtree != NULL)
00476 {
00477 my_userdata data = { node->newtree, section };
00478 node->newtree->visit(
00479 UniConfValueTree::Visitor(
00480 this, &UniTransactionGen::deletion_visitor),
00481 (void *)&data, false, true);
00482 }
00483 }
00484 else
00485 cancel_values(node->newtree, section);
00486 return;
00487 }
00488
00489 WvString value;
00490 if (node->mode != BLANK)
00491 value = base->get(section);
00492
00493 if (node->mode == NEWVALUE &&
00494 !value.isnull() &&
00495 value != node->newvalue)
00496 delta(section, value);
00497
00498 UniConfChangeTree::Iter i(*node);
00499 for (i.rewind(); i.next();)
00500 cancel_changes(i.ptr(), UniConfKey(section, i->key()));
00501
00502 if (node->mode != BLANK && value.isnull())
00503 delta(section, WvString::null);
00504 }
00505
00506 void UniTransactionGen::gencallback(const UniConfKey &key,
00507 WvStringParm value)
00508 {
00509 UniConfChangeTree *node = root;
00510 for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00511 {
00512 if (!node)
00513
00514
00515
00516 break;
00517 else if (node->mode == NEWTREE)
00518
00519
00520
00521
00522 return;
00523 else if (seg == key.numsegments())
00524 {
00525
00526
00527 if (node->mode == NEWVALUE)
00528
00529
00530 return;
00531 else if (node->mode == NEWNODE)
00532 {
00533
00534
00535
00536 if (node->was_null_or_empty && !value)
00537 return;
00538 node->was_null_or_empty = !value;
00539 if (value.isnull())
00540 {
00541 delta(key, WvString::empty);
00542 return;
00543 }
00544 break;
00545 }
00546 else
00547
00548
00549 break;
00550 }
00551 }
00552
00553
00554 delta(key, value);
00555 }
00556
00557
00558
00559
00560
00561
00562 UniConfValueTree *UniTransactionGen::create_value(UniConfValueTree *parent,
00563 const UniConfKey &key,
00564 int seg,
00565 WvStringParm value)
00566 {
00567 UniConfValueTree *tree = 0;
00568 for (; seg != key.numsegments();)
00569 {
00570
00571
00572 parent = new UniConfValueTree(parent,
00573 key.segment(seg-1),
00574 WvString::empty);
00575 delta(key.first(seg++), WvString::empty);
00576 if (!tree)
00577 tree = parent;
00578 }
00579
00580 parent = new UniConfValueTree(parent,
00581 key.segment(seg-1),
00582 value);
00583 delta(key, value);
00584 if (!tree)
00585 tree = parent;
00586 return tree;
00587 }
00588
00589 void UniTransactionGen::deletion_simulator(const UniConfKey &key)
00590 {
00591 UniConfGen::Iter *i = base->iterator(key);
00592 if (i)
00593 {
00594 for (i->rewind(); i->next();)
00595 deletion_simulator(UniConfKey(key, i->key()));
00596 delete i;
00597 }
00598 delta(key, WvString::null);
00599 }
00600
00601
00602
00603 UniConfChangeTree *UniTransactionGen::create_change(UniConfChangeTree *parent,
00604 const UniConfKey &key,
00605 int seg,
00606 WvStringParm value)
00607 {
00608 UniConfChangeTree *tree = 0;
00609 for (; seg != key.numsegments(); seg++)
00610 {
00611 parent = new UniConfChangeTree(parent, key.segment(seg-1));
00612 if (value.isnull())
00613
00614 parent->mode = BLANK;
00615 else
00616 {
00617
00618 parent->mode = NEWNODE;
00619 UniConfKey nodekey(key.first(seg));
00620 WvString curr = base->get(nodekey);
00621 parent->was_null_or_empty = !curr;
00622 if (curr.isnull())
00623 delta(nodekey, WvString::empty);
00624 }
00625 if (!tree)
00626 tree = parent;
00627 }
00628 parent = new UniConfChangeTree(parent, key.segment(seg-1));
00629
00630 if (value.isnull())
00631 {
00632 parent->mode = NEWTREE;
00633 parent->newtree = 0;
00634 if (base->exists(key))
00635 deletion_simulator(key);
00636 }
00637 else
00638 {
00639 parent->mode = NEWVALUE;
00640 parent->newvalue = WvString(value);
00641 if (base->get(key) != value)
00642 delta(key, value);
00643 }
00644 if (!tree)
00645 tree = parent;
00646 return tree;
00647 }
00648
00649
00650
00651
00652
00653 UniConfValueTree *UniTransactionGen::set_value(UniConfValueTree *node,
00654 const UniConfKey &key,
00655 int seg,
00656 WvStringParm value)
00657 {
00658
00659 if (value.isnull())
00660 {
00661
00662 if (node)
00663 {
00664 UniConfValueTree *subnode = node->find(
00665 key.last(key.numsegments() - seg));
00666 if (subnode)
00667 {
00668 hold_delta();
00669 my_userdata data = { subnode, key };
00670 subnode->visit(
00671 UniConfValueTree::Visitor(
00672 this, &UniTransactionGen::deletion_visitor),
00673 (void *)&data, false, true);
00674
00675 delete subnode;
00676 unhold_delta();
00677 return subnode == node ? NULL : node;
00678 }
00679 else
00680 return node;
00681 }
00682 else
00683 return NULL;
00684 }
00685 else
00686 {
00687
00688 if (!node)
00689 return create_value(NULL, key, seg, value);
00690
00691 UniConfValueTree *subnode = node;
00692 for (; seg != key.numsegments();)
00693 {
00694 UniConfKey segment(key.segment(seg++));
00695 UniConfValueTree *child = subnode->findchild(segment);
00696
00697 if (!child)
00698 {
00699 create_value(subnode, key, seg, value);
00700 return node;
00701 }
00702 else
00703 subnode = child;
00704 }
00705
00706 if (value != subnode->value())
00707 {
00708 subnode->setvalue(value);
00709 delta(key, value);
00710 }
00711 return node;
00712 }
00713 }
00714
00715 void UniTransactionGen::deletion_simulator2(const UniConfKey &key)
00716 {
00717 UniConfGen::Iter *i = this->iterator(key);
00718 if (i)
00719 {
00720 for (i->rewind(); i->next();)
00721 deletion_simulator2(UniConfKey(key, i->key()));
00722 delete i;
00723 }
00724 delta(key, WvString::null);
00725 }
00726
00727
00728 UniConfChangeTree *UniTransactionGen::set_change(UniConfChangeTree *node,
00729 const UniConfKey &key,
00730 int seg,
00731 WvStringParm value)
00732 {
00733
00734
00735
00736
00737
00738 if (!node)
00739 return create_change(NULL, key, seg, value);
00740 else if (node->mode == NEWTREE)
00741 {
00742 node->newtree = set_value(node->newtree, key, seg, value);
00743 return node;
00744 }
00745
00746 UniConfChangeTree *subnode = node;
00747 for (; seg != key.numsegments();)
00748 {
00749 if (subnode->mode == BLANK && !value.isnull())
00750 {
00751
00752
00753 subnode->mode = NEWNODE;
00754 UniConfKey nodekey(key.first(seg));
00755 WvString curr = base->get(nodekey);
00756 subnode->was_null_or_empty = !curr;
00757 if (curr.isnull())
00758 delta(nodekey, WvString::empty);
00759 }
00760
00761 UniConfKey segment(key.segment(seg++));
00762 UniConfChangeTree *next = subnode->findchild(segment);
00763
00764
00765 if (!next)
00766 {
00767 create_change(subnode, key, seg, value);
00768 return node;
00769 }
00770 else if (next->mode == NEWTREE)
00771 {
00772 next->newtree = set_value(next->newtree,
00773 key, seg, value);
00774 return node;
00775 }
00776 else
00777 subnode = next;
00778 }
00779
00780
00781 if (value.isnull())
00782 {
00783 if (subnode->mode != BLANK || base->exists(key))
00784 deletion_simulator2(key);
00785 subnode->zap();
00786 subnode->mode = NEWTREE;
00787 subnode->newtree = 0;
00788 }
00789 else if (subnode->mode == NEWVALUE)
00790 {
00791 if (subnode->newvalue != value)
00792 {
00793 subnode->newvalue = value;
00794 delta(key, value);
00795 }
00796 }
00797 else if (subnode->mode == BLANK)
00798 {
00799 if (base->get(key) != value)
00800 delta(key, value);
00801 subnode->mode = NEWVALUE;
00802 subnode->newvalue = WvString(value);
00803 }
00804 else
00805 {
00806 WvString currval(base->get(key));
00807 if ((!currval != !value) && (currval != value))
00808 delta(key, value);
00809 subnode->mode = NEWVALUE;
00810 subnode->newvalue = WvString(value);
00811 }
00812 return node;
00813 }
00814
00815
00816 bool UniTransactionGen::isok()
00817 {
00818 return base->isok();
00819 }
00820
00821 void UniTransactionGen::flush_buffers()
00822 {
00823 }