00001 #include "unitransactiongen.h"
00002 #include "uniconftree.h"
00003 #include "unilistiter.h"
00004 #include "wvmoniker.h"
00005
00006 static IUniConfGen *creator(WvStringParm s, IObject *_obj)
00007 {
00008 IUniConfGen *base = wvcreate<IUniConfGen>(s, _obj);
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, wv::bind(&UniTransactionGen::gencallback, this,
00206 _1, _2));
00207 }
00208
00209 UniTransactionGen::~UniTransactionGen()
00210 {
00211 base->del_callback(this);
00212 WVRELEASE(base);
00213 WVDELETE(root);
00214 }
00215
00216 WvString UniTransactionGen::get(const UniConfKey &key)
00217 {
00218 UniConfChangeTree *node = root;
00219 for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00220 {
00221 if (!node)
00222
00223
00224
00225 return base->get(key);
00226 else if (node->mode == NEWTREE)
00227 {
00228
00229
00230
00231 if (node->newtree)
00232 {
00233 UniConfValueTree *subnode = node->newtree->find(
00234 key.last(key.numsegments() - seg));
00235 if (subnode)
00236 return subnode->value();
00237 }
00238 return WvString::null;
00239 }
00240 else if (seg == key.numsegments())
00241 {
00242
00243
00244
00245 if (node->mode == NEWVALUE)
00246 return node->newvalue;
00247 WvString value(base->get(key.first(seg)));
00248 return (node->mode == NEWNODE && !value) ? WvString::empty : value;
00249 }
00250 }
00251 }
00252
00253 void UniTransactionGen::set(const UniConfKey &key, WvStringParm value)
00254 {
00255 hold_delta();
00256 root = set_change(root, key, 0, value);
00257 unhold_delta();
00258 }
00259
00260 void UniTransactionGen::setv(const UniConfPairList &pairs)
00261 {
00262 hold_delta();
00263 UniConfPairList::Iter i(pairs);
00264 for (i.rewind(); i.next(); )
00265 root = set_change(root, i->key(), 0, i->value());
00266 unhold_delta();
00267 }
00268
00269 void UniTransactionGen::commit()
00270 {
00271 if (root)
00272 {
00273
00274
00275
00276 hold_delta();
00277 apply_changes(root, UniConfKey());
00278
00279
00280 base->commit();
00281
00282
00283
00284 delete root;
00285 root = NULL;
00286 unhold_delta();
00287 }
00288
00289
00290 }
00291
00292 bool UniTransactionGen::refresh()
00293 {
00294 if (root)
00295 {
00296 hold_delta();
00297 cancel_changes(root, UniConfKey());
00298 delete root;
00299 root = NULL;
00300 unhold_delta();
00301
00302
00303
00304 }
00305
00306
00307 return base->refresh();
00308 }
00309
00310 UniConfGen::Iter *UniTransactionGen::iterator(const UniConfKey &key)
00311 {
00312 UniConfChangeTree *node = root;
00313 for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00314 {
00315 if (!node)
00316
00317
00318
00319 return base->iterator(key);
00320 else if (node->mode == NEWTREE)
00321 {
00322
00323
00324
00325 if (node->newtree)
00326 {
00327 UniConfValueTree *subnode = node->newtree->find(
00328 key.last(key.numsegments() - seg));
00329 if (subnode)
00330 {
00331 UniConfGen::Iter *i = new GenStyleValueTreeIter(subnode);
00332 UniListIter *i2 = new UniListIter(this);
00333 i2->autofill(i);
00334 delete i;
00335 return i2;
00336 }
00337 }
00338 return new UniConfGen::NullIter();
00339 }
00340 else if (seg == key.numsegments())
00341 {
00342
00343
00344 UniConfGen::Iter *i = new GenStyleChangeTreeIter(node, key, base);
00345 UniListIter *i2 = new UniListIter(this);
00346 i2->autofill(i);
00347 delete i;
00348 return i2;
00349 }
00350 }
00351 }
00352
00353 void UniTransactionGen::apply_values(UniConfValueTree *newcontents,
00354 const UniConfKey §ion)
00355 {
00356 base->set(section, newcontents->value());
00357
00358 UniConfGen::Iter *j = base->iterator(section);
00359 if (j)
00360 {
00361 for (j->rewind(); j->next();)
00362 {
00363 if (newcontents->findchild(j->key()) == NULL)
00364
00365
00366
00367 base->set(UniConfKey(section, j->key()), WvString::null);
00368 }
00369 delete j;
00370 }
00371
00372
00373 UniConfValueTree::Iter i(*newcontents);
00374 for (i.rewind(); i.next();)
00375 apply_values(i.ptr(), UniConfKey(section, i->key()));
00376 }
00377
00378 void UniTransactionGen::apply_changes(UniConfChangeTree *node,
00379 const UniConfKey §ion)
00380 {
00381 if (node->mode == NEWTREE)
00382 {
00383
00384
00385 if (node->newtree == NULL)
00386 base->set(section, WvString::null);
00387 else
00388 apply_values(node->newtree, section);
00389
00390 return;
00391 }
00392 else if (node->mode == NEWVALUE)
00393 {
00394
00395 base->set(section, node->newvalue);
00396 }
00397 else if (node->mode == NEWNODE)
00398 {
00399
00400 if (!base->exists(section))
00401
00402
00403 base->set(section, WvString::empty);
00404
00405
00406
00407 }
00408
00409
00410 UniConfChangeTree::Iter i(*node);
00411 for (i.rewind(); i.next();)
00412 apply_changes(i.ptr(), UniConfKey(section, i->key()));
00413 }
00414
00415 struct my_userdata
00416 {
00417 UniConfValueTree *node;
00418 const UniConfKey &key;
00419 };
00420
00421 void UniTransactionGen::deletion_visitor(const UniConfValueTree *node,
00422 void *userdata)
00423 {
00424 my_userdata *data = (my_userdata *)userdata;
00425 delta(UniConfKey(data->key, node->fullkey(data->node)), WvString::null);
00426 }
00427
00428
00429
00430 void UniTransactionGen::cancel_values(UniConfValueTree *newcontents,
00431 const UniConfKey §ion)
00432 {
00433 WvString value(base->get(section));
00434 if (!newcontents || newcontents->value() != value)
00435 delta(section, value);
00436
00437 if (newcontents)
00438 {
00439 UniConfValueTree::Iter i(*newcontents);
00440 for (i.rewind(); i.next();)
00441 {
00442 UniConfKey subkey(section, i->key());
00443 if (!base->exists(subkey))
00444 {
00445 my_userdata data = { i.ptr(), subkey };
00446 i->visit(wv::bind(&UniTransactionGen::deletion_visitor, this,
00447 _1, _2),
00448 (void*)&data, false, true);
00449 }
00450 }
00451 }
00452
00453 UniConfGen::Iter *i = base->iterator(section);
00454 if (i)
00455 {
00456 for (i->rewind(); i->next();)
00457 cancel_values(newcontents ?
00458 newcontents->findchild(i->key()) : NULL,
00459 UniConfKey(section, i->key()));
00460 delete i;
00461 }
00462 }
00463
00464
00465
00466 void UniTransactionGen::cancel_changes(UniConfChangeTree *node,
00467 const UniConfKey §ion)
00468 {
00469 if (node->mode == NEWTREE)
00470 {
00471 if (!base->exists(section))
00472 {
00473 if (node->newtree != NULL)
00474 {
00475 my_userdata data = { node->newtree, section };
00476 node->newtree->visit(
00477 wv::bind(&UniTransactionGen::deletion_visitor, this,
00478 _1, _2),
00479 (void *)&data, false, true);
00480 }
00481 }
00482 else
00483 cancel_values(node->newtree, section);
00484 return;
00485 }
00486
00487 WvString value;
00488 if (node->mode != BLANK)
00489 value = base->get(section);
00490
00491 if (node->mode == NEWVALUE &&
00492 !value.isnull() &&
00493 value != node->newvalue)
00494 delta(section, value);
00495
00496 UniConfChangeTree::Iter i(*node);
00497 for (i.rewind(); i.next();)
00498 cancel_changes(i.ptr(), UniConfKey(section, i->key()));
00499
00500 if (node->mode != BLANK && value.isnull())
00501 delta(section, WvString::null);
00502 }
00503
00504 void UniTransactionGen::gencallback(const UniConfKey &key,
00505 WvStringParm value)
00506 {
00507 UniConfChangeTree *node = root;
00508 for (int seg = 0;; node = node->findchild(key.segment(seg++)))
00509 {
00510 if (!node)
00511
00512
00513
00514 break;
00515 else if (node->mode == NEWTREE)
00516
00517
00518
00519
00520 return;
00521 else if (seg == key.numsegments())
00522 {
00523
00524
00525 if (node->mode == NEWVALUE)
00526
00527
00528 return;
00529 else if (node->mode == NEWNODE)
00530 {
00531
00532
00533
00534 if (node->was_null_or_empty && !value)
00535 return;
00536 node->was_null_or_empty = !value;
00537 if (value.isnull())
00538 {
00539 delta(key, WvString::empty);
00540 return;
00541 }
00542 break;
00543 }
00544 else
00545
00546
00547 break;
00548 }
00549 }
00550
00551
00552 delta(key, value);
00553 }
00554
00555
00556
00557
00558
00559
00560 UniConfValueTree *UniTransactionGen::create_value(UniConfValueTree *parent,
00561 const UniConfKey &key,
00562 int seg,
00563 WvStringParm value)
00564 {
00565 UniConfValueTree *tree = 0;
00566 for (; seg != key.numsegments();)
00567 {
00568
00569
00570 parent = new UniConfValueTree(parent,
00571 key.segment(seg-1),
00572 WvString::empty);
00573 delta(key.first(seg++), WvString::empty);
00574 if (!tree)
00575 tree = parent;
00576 }
00577
00578 parent = new UniConfValueTree(parent,
00579 key.segment(seg-1),
00580 value);
00581 delta(key, value);
00582 if (!tree)
00583 tree = parent;
00584 return tree;
00585 }
00586
00587 void UniTransactionGen::deletion_simulator(const UniConfKey &key)
00588 {
00589 UniConfGen::Iter *i = base->iterator(key);
00590 if (i)
00591 {
00592 for (i->rewind(); i->next();)
00593 deletion_simulator(UniConfKey(key, i->key()));
00594 delete i;
00595 }
00596 delta(key, WvString::null);
00597 }
00598
00599
00600
00601 UniConfChangeTree *UniTransactionGen::create_change(UniConfChangeTree *parent,
00602 const UniConfKey &key,
00603 int seg,
00604 WvStringParm value)
00605 {
00606
00607
00608 if ((key.hastrailingslash()) && !value.isnull())
00609 return parent;
00610
00611 UniConfChangeTree *tree = 0;
00612 for (; seg != key.numsegments(); seg++)
00613 {
00614 parent = new UniConfChangeTree(parent, key.segment(seg-1));
00615 if (value.isnull())
00616
00617 parent->mode = BLANK;
00618 else
00619 {
00620
00621 parent->mode = NEWNODE;
00622 UniConfKey nodekey(key.first(seg));
00623 WvString curr = base->get(nodekey);
00624 parent->was_null_or_empty = !curr;
00625 if (curr.isnull())
00626 delta(nodekey, WvString::empty);
00627 }
00628 if (!tree)
00629 tree = parent;
00630 }
00631 parent = new UniConfChangeTree(parent, key.segment(seg-1));
00632
00633 if (value.isnull())
00634 {
00635 parent->mode = NEWTREE;
00636 parent->newtree = 0;
00637 if (base->exists(key))
00638 deletion_simulator(key);
00639 }
00640 else
00641 {
00642 parent->mode = NEWVALUE;
00643 parent->newvalue = WvString(value);
00644 if (base->get(key) != value)
00645 delta(key, value);
00646 }
00647 if (!tree)
00648 tree = parent;
00649 return tree;
00650 }
00651
00652
00653
00654
00655
00656 UniConfValueTree *UniTransactionGen::set_value(UniConfValueTree *node,
00657 const UniConfKey &key,
00658 int seg,
00659 WvStringParm value)
00660 {
00661
00662 if (value.isnull())
00663 {
00664
00665 if (node)
00666 {
00667 UniConfValueTree *subnode = node->find(
00668 key.last(key.numsegments() - seg));
00669 if (subnode)
00670 {
00671 hold_delta();
00672 my_userdata data = { subnode, key };
00673 subnode->visit(wv::bind(&UniTransactionGen::deletion_visitor,
00674 this, _1, _2),
00675 (void *)&data, false, true);
00676
00677 delete subnode;
00678 unhold_delta();
00679 return subnode == node ? NULL : node;
00680 }
00681 else
00682 return node;
00683 }
00684 else
00685 return NULL;
00686 }
00687 else
00688 {
00689
00690 if (!node)
00691 return create_value(NULL, key, seg, value);
00692
00693 UniConfValueTree *subnode = node;
00694 for (; seg != key.numsegments();)
00695 {
00696 UniConfKey segment(key.segment(seg++));
00697 UniConfValueTree *child = subnode->findchild(segment);
00698
00699 if (!child)
00700 {
00701 create_value(subnode, key, seg, value);
00702 return node;
00703 }
00704 else
00705 subnode = child;
00706 }
00707
00708 if (value != subnode->value())
00709 {
00710 subnode->setvalue(value);
00711 delta(key, value);
00712 }
00713 return node;
00714 }
00715 }
00716
00717 void UniTransactionGen::deletion_simulator2(const UniConfKey &key)
00718 {
00719 UniConfGen::Iter *i = this->iterator(key);
00720 if (i)
00721 {
00722 for (i->rewind(); i->next();)
00723 deletion_simulator2(UniConfKey(key, i->key()));
00724 delete i;
00725 }
00726 delta(key, WvString::null);
00727 }
00728
00729
00730 UniConfChangeTree *UniTransactionGen::set_change(UniConfChangeTree *node,
00731 const UniConfKey &key,
00732 int seg,
00733 WvStringParm value)
00734 {
00735
00736
00737
00738
00739
00740 if (!node)
00741 return create_change(NULL, key, seg, value);
00742 else if (node->mode == NEWTREE)
00743 {
00744 node->newtree = set_value(node->newtree, key, seg, value);
00745 return node;
00746 }
00747
00748 UniConfChangeTree *subnode = node;
00749 for (; seg != key.numsegments();)
00750 {
00751 if (subnode->mode == BLANK && !value.isnull())
00752 {
00753
00754
00755 subnode->mode = NEWNODE;
00756 UniConfKey nodekey(key.first(seg));
00757 WvString curr = base->get(nodekey);
00758 subnode->was_null_or_empty = !curr;
00759 if (curr.isnull())
00760 delta(nodekey, WvString::empty);
00761 }
00762
00763 UniConfKey segment(key.segment(seg++));
00764 UniConfChangeTree *next = subnode->findchild(segment);
00765
00766
00767 if (!next)
00768 {
00769 create_change(subnode, key, seg, value);
00770 return node;
00771 }
00772 else if (next->mode == NEWTREE)
00773 {
00774 next->newtree = set_value(next->newtree,
00775 key, seg, value);
00776 return node;
00777 }
00778 else
00779 subnode = next;
00780 }
00781
00782
00783 if (value.isnull())
00784 {
00785 if (subnode->mode != BLANK || base->exists(key))
00786 deletion_simulator2(key);
00787 subnode->zap();
00788 subnode->mode = NEWTREE;
00789 subnode->newtree = 0;
00790 }
00791 else if (subnode->mode == NEWVALUE)
00792 {
00793 if (subnode->newvalue != value)
00794 {
00795 subnode->newvalue = value;
00796 delta(key, value);
00797 }
00798 }
00799 else if (subnode->mode == BLANK)
00800 {
00801 if (base->get(key) != value)
00802 delta(key, value);
00803 subnode->mode = NEWVALUE;
00804 subnode->newvalue = WvString(value);
00805 }
00806 else
00807 {
00808 WvString currval(base->get(key));
00809 if ((!currval != !value) && (currval != value))
00810 delta(key, value);
00811 subnode->mode = NEWVALUE;
00812 subnode->newvalue = WvString(value);
00813 }
00814 return node;
00815 }
00816
00817
00818 bool UniTransactionGen::isok()
00819 {
00820 return base->isok();
00821 }
00822
00823 void UniTransactionGen::flush_buffers()
00824 {
00825 }