1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.model;
20
21 import java.io.Serializable;
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.NoSuchElementException;
32 import java.util.Set;
33 import java.util.Stack;
34
35 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
36
37
38
39
40
41
42
43
44
45 public class RowKeySetTreeImpl extends RowKeySet implements Serializable
46 {
47
48
49
50 public RowKeySetTreeImpl()
51 {
52 this(false);
53 }
54
55
56
57
58
59 public RowKeySetTreeImpl(boolean addAll)
60 {
61 _root = new Node<Object>(addAll);
62 }
63
64
65
66
67
68 @Override
69 public boolean contains(Object rowKey)
70 {
71 return _isContained(rowKey);
72 }
73
74
75
76
77 @Override
78 @Deprecated
79 public boolean isContainedByDefault()
80 {
81 TreeModel model = getCollectionModel();
82
83 if (model != null)
84 {
85 Object rowkey = model.getRowKey();
86 return new Search().find(rowkey).isDefaultContained;
87 }
88 return false;
89 }
90
91 @Override
92 public Iterator<Object> iterator()
93 {
94 if(_root.isDefaultContained)
95 return new PathIterator();
96 else
97 return new NodeIterator();
98 }
99
100
101
102
103
104
105
106 @Override
107 public boolean add(Object rowKey)
108 {
109 return _setContained(rowKey, true);
110 }
111
112
113
114
115
116
117
118 @Override
119 public boolean remove(Object rowKey)
120 {
121 return _setContained(rowKey, false);
122 }
123
124
125
126
127
128
129
130 @Override
131 public void addAll()
132 {
133 _selectAll(true);
134 }
135
136
137
138
139
140
141
142
143 @Override
144 public void removeAll()
145 {
146 _selectAll(false);
147 }
148
149
150
151
152
153
154
155 @Override
156 public boolean addAll(Collection<? extends Object> other)
157 {
158 if (other instanceof RowKeySetTreeImpl)
159 {
160 RowKeySetTreeImpl otherset = (RowKeySetTreeImpl) other;
161 return _processOperation(this._root, otherset._root, true);
162 }
163 return super.addAll(other);
164 }
165
166
167
168
169
170
171
172 @Override
173 public boolean removeAll(Collection<?> other)
174 {
175 if (other instanceof RowKeySetTreeImpl)
176 {
177 RowKeySetTreeImpl otherset = (RowKeySetTreeImpl) other;
178 return _processOperation(this._root, otherset._root, false);
179 }
180 return super.removeAll(other);
181 }
182
183 private boolean _processOperation(Node<Object> set1, Node<Object> set2, boolean add)
184 {
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 boolean hasChanges = false;
205
206
207
208
209 if (set2.isDefaultContained && set1.keySet().retainAll(set2.keySet()))
210 hasChanges = true;
211
212
213
214
215
216
217
218
219
220
221 boolean addAll = add ^ set1.isDefaultContained;
222
223 for(Entry<Object, Node<Object>> en:set2.entrySet())
224 {
225 Object segment = en.getKey();
226 Node<Object> subset2 = en.getValue();
227 Node<Object> subset1 = set1.get(segment);
228
229 if (subset1 == null)
230 {
231 if (addAll)
232 {
233 subset1 = new Node<Object>(set1, segment);
234 hasChanges = true;
235 }
236 else
237 continue;
238 }
239 if (_processOperation(subset1, subset2, add))
240 hasChanges = true;
241 }
242
243
244
245
246 if (set2.isDefaultContained && (set1.isDefaultContained != add))
247 {
248 set1.isDefaultContained = add;
249
250
251 set1.isDifferent = !set1.isDifferent;
252 hasChanges = true;
253 }
254
255
256
257 if ((set2.isDefaultContained ^ set2.isDifferent) &&
258 ((set1.isDefaultContained ^ set1.isDifferent) != add))
259 {
260 set1.isDifferent = !set1.isDifferent;
261 hasChanges = true;
262 }
263
264 return hasChanges;
265 }
266
267
268
269
270
271
272 @Override
273 public void clear()
274 {
275 _root.clear();
276 _root.isDefaultContained = _root.isDifferent = false;
277 }
278
279
280
281
282
283
284 @Override
285 public int getSize()
286 {
287 return _getSize(null, _root, getCollectionModel(), false);
288 }
289
290
291
292
293
294
295 @Override
296 public int size()
297 {
298 return _getSize(null, _root, getCollectionModel(), true);
299 }
300
301 @Override
302 public boolean isEmpty()
303 {
304 return (getSize() == 0);
305 }
306
307
308
309
310
311 @Override
312 public final void setCollectionModel(CollectionModel model)
313 {
314 if (model != null && !(model instanceof TreeModel))
315 throw new IllegalArgumentException();
316
317 _model = (TreeModel) model;
318 }
319
320
321
322
323
324 @Override
325 public RowKeySetTreeImpl clone()
326 {
327 RowKeySetTreeImpl clone = (RowKeySetTreeImpl) super.clone();
328 clone._root = _root.clone();
329 return clone;
330 }
331
332
333
334
335 @Deprecated
336 @Override
337 public void invertAll()
338 {
339
340 throw new UnsupportedOperationException();
341 }
342
343
344
345
346
347
348
349 @Override
350 protected TreeModel getCollectionModel()
351 {
352 return _model;
353 }
354
355
356
357
358
359
360
361
362
363 @SuppressWarnings("unchecked")
364 private int _getTreeSize(TreeModel model, Set<Object> exclusions)
365 {
366 int sz = 0;
367 for(int i=0;true;i++)
368 {
369 model.setRowIndex(i);
370 if (model.isRowAvailable())
371 {
372 Object rowkey = model.getRowKey();
373 if (exclusions.contains(rowkey))
374 continue;
375 sz++;
376 if (model.isContainer())
377 {
378 model.enterContainer();
379 Set<Object> empty = Collections.emptySet();
380 sz += _getTreeSize(model, empty);
381 model.exitContainer();
382 }
383 }
384 else
385 return sz;
386 }
387 }
388
389 private int _getSize(Object rowkey, Node<Object> set, TreeModel model, boolean fetchall)
390 {
391
392 int sz = ((rowkey != null) && (set.isDefaultContained ^ set.isDifferent)) ? 1 : 0;
393 if (set.isDefaultContained)
394 {
395 if (!fetchall || model == null)
396 return -1;
397
398 Object old = model.getRowKey();
399 try
400 {
401 model.setRowKey(rowkey);
402
403 if (rowkey == null)
404 {
405 sz += _getTreeSize(model, set.keySet());
406 }
407 else if (model.isContainer())
408 {
409 model.enterContainer();
410 sz += _getTreeSize(model, set.keySet());
411 }
412 }
413 finally
414 {
415 model.setRowKey(old);
416 }
417 }
418
419 for(Entry<Object, Node<Object>> en:set.entrySet())
420 {
421 Object newrowkey = en.getKey();
422 Node<Object> subset = en.getValue();
423 int size = _getSize(newrowkey, subset, model, fetchall);
424 if (size < 0)
425 return -1;
426 sz+= size;
427 }
428 return sz;
429 }
430
431
432
433
434
435 private void _selectAll(final boolean isSelectAll)
436 {
437 Search search = new Search()
438 {
439 @Override
440 protected boolean create(Node<Object> parent, Object rowkey)
441 {
442
443
444
445 return (parent.isDefaultContained != isSelectAll);
446 }
447
448 @Override
449 protected Node<Object> found(Node<Object> child)
450 {
451 child.isDefaultContained = isSelectAll;
452 child.isDifferent = false;
453 child.clear();
454 return null;
455 }
456 };
457
458 TreeModel model = getCollectionModel();
459 Object rowkey = model.getRowKey();
460 search.find(rowkey);
461 }
462
463 private boolean _isContained(Object rowkey)
464 {
465 Search search = new Search()
466 {
467 @Override
468 protected Node<Object> notFound(Node<Object> parent, Object rowkey)
469 {
470 return parent.isDefaultContained ? parent : null;
471 }
472
473 @Override
474 protected Node<Object> found(Node<Object> child)
475 {
476 return (child.isDefaultContained ^ child.isDifferent) ? child : null;
477 }
478 };
479
480 return (search.find(rowkey) != null);
481 }
482
483
484
485
486
487
488
489 private boolean _setContained(Object rowkey, final boolean isContained)
490 {
491 Search search = new Search()
492 {
493 @Override
494 protected boolean create(Node<Object> parent, Object rowkey)
495 {
496
497
498 return parent.isDefaultContained != isContained;
499 }
500
501 @Override
502 protected Node<Object> notFound(Node<Object> parent, Object rowkey)
503 {
504 return null;
505 }
506 };
507
508 Node<Object> current = search.find(rowkey);
509 if ((current != null) &&
510 ((current.isDefaultContained ^ current.isDifferent) != isContained))
511 {
512 current.isDifferent = !current.isDifferent;
513 return true;
514 }
515 return false;
516 }
517
518
519
520
521
522
523
524
525
526
527 private static boolean _advanceToNextItem(
528 TreeModel model, int minDepth, boolean recurseChildren)
529 {
530 assert minDepth >= 0;
531
532 if (recurseChildren && model.isRowAvailable() && model.isContainer())
533 {
534 model.enterContainer();
535 model.setRowIndex(-1);
536 }
537 while(true)
538 {
539 int ri = model.getRowIndex();
540 model.setRowIndex(ri+1);
541 if (model.isRowAvailable())
542 return true;
543
544 int depth = model.getDepth();
545 if (depth <= minDepth)
546 return false;
547
548 model.exitContainer();
549 }
550 }
551
552
553
554
555
556 private boolean _containsDefaultNodes()
557 {
558 if(_root.isDefaultContained)
559 return true;
560
561 SetLoop loop = new SetLoop()
562 {
563 protected boolean next(Object rowKey, Node<Object> value)
564 {
565 return value.isDefaultContained;
566 }
567 };
568 return loop.run(_root);
569 }
570
571
572
573
574 private void _dumpFlags()
575 {
576 System.out.println("root " + _root.isDefaultContained + " " + _root.isDifferent);
577 SetLoop loop = new SetLoop()
578 {
579 protected boolean next(Object rowKey, Node<Object> value)
580 {
581 System.out.println(rowKey + " " + value.isDefaultContained + " " + value.isDifferent);
582 return false;
583 }
584 };
585 loop.run(_root);
586 }
587
588
589 private static final class Node<K> extends LinkedHashMap<K, Node<K>>
590
591 {
592 public boolean isDifferent = false;
593 public boolean isDefaultContained = false;
594
595 public Node(boolean isDefaultContained)
596 {
597 this.isDefaultContained = isDefaultContained;
598 }
599
600 public Node(Node<K> parent, K segment)
601 {
602 this(parent.isDefaultContained);
603 parent.put(segment, this);
604 }
605
606
607 private void _deepClone(Node<K> root)
608 {
609 for(Entry<K, Node<K>> en:root.entrySet())
610 {
611 Node<K> original = en.getValue();
612 Node<K> clone = original.clone();
613 en.setValue(clone);
614 }
615 }
616
617 @SuppressWarnings("unchecked")
618 @Override
619 public Node<K> clone()
620 {
621 Node<K> clone = (Node<K>) super.clone();
622 _deepClone(clone);
623 return clone;
624 }
625
626 private static final long serialVersionUID = 1L;
627 }
628
629 private class Search
630 {
631 public Search()
632 {
633 }
634
635 protected boolean create(Node<Object> parent, Object rowkey)
636 {
637 return false;
638 }
639
640 protected Node<Object> notFound(Node<Object> parent, Object rowkey)
641 {
642 return parent;
643 }
644
645 protected Node<Object> found(Node<Object> result)
646 {
647 return result;
648 }
649
650 public Node<Object> find(Object rowkey)
651 {
652 Node<Object> current = _root;
653 if (rowkey != null)
654 {
655 TreeModel model = getCollectionModel();
656 if (model == null)
657 {
658 return notFound(current, rowkey);
659 }
660 List<Object> parentkeys = model.getAllAncestorContainerRowKeys(rowkey);
661 List<Object> allkeys = new ArrayList<Object>(parentkeys.size() + 1);
662 allkeys.addAll(parentkeys);
663 allkeys.add(rowkey);
664 for(Object key:allkeys)
665 {
666 Node<Object> next = current.get(key);
667 if (next == null)
668 {
669 if (create(current, key))
670 next = new Node<Object>(current, key);
671 else
672 return notFound(current, key);
673 }
674 current = next;
675 }
676 }
677 return found(current);
678 }
679 }
680
681
682
683
684
685 private static abstract class SetLoop
686 {
687 public SetLoop()
688 {
689 }
690
691 public boolean run (Node<Object> set)
692 {
693 for(Entry<Object, Node<Object>> en : set.entrySet())
694 {
695 Object keyEnt = en.getKey();
696 Node<Object> subset = en.getValue();
697 if(next(keyEnt, subset))
698 return true;
699 if(run(subset))
700 return true;
701 }
702 return false;
703 }
704
705 protected abstract boolean next(Object rowKey, Node<Object> value );
706 }
707
708 private class PathIterator implements Iterator<Object>
709 {
710 PathIterator()
711 {
712 _value = (getCollectionModel() == null || isEmpty()) ? null : nextItem();
713 }
714
715 PathIterator(Object noop)
716 {
717 }
718
719 public Object next()
720 {
721 if (!hasNext())
722 throw new NoSuchElementException();
723 Object value = _value;
724 _value = nextItem();
725 return value;
726 }
727
728 public boolean hasNext()
729 {
730 return (_value != null);
731 }
732
733 public void remove()
734 {
735 throw new UnsupportedOperationException();
736 }
737
738 protected Object nextItem()
739 {
740 return nextModelKey(0);
741 }
742
743 protected Object nextModelKey(int minDepth)
744 {
745 TreeModel model = getCollectionModel();
746 if (model == null)
747 return null;
748
749 Object oldPath = model.getRowKey();
750 try
751 {
752 model.setRowKey(_currPath);
753 while(true)
754 {
755 boolean searchChildren = _containsSubtree(_currPath);
756 boolean hasMore = _advanceToNextItem(model, minDepth, searchChildren);
757 if (!hasMore)
758 return null;
759
760 _currPath = model.getRowKey();
761 if (contains(_currPath))
762 return _currPath;
763 }
764 }
765 finally
766 {
767 model.setRowKey(oldPath);
768 }
769 }
770
771 private boolean _containsSubtree(Object rowkey)
772 {
773 Search search = new Search()
774 {
775 @Override
776 protected Node<Object> notFound(Node<Object> parent, Object rowkey)
777 {
778 return parent.isDefaultContained ? parent : null;
779 }
780 };
781 Node<Object> current = search.find(rowkey);
782 return (current != null) &&
783 ((!current.isEmpty()) || current.isDefaultContained);
784 }
785
786 protected Object _value;
787 protected Object _currPath = null;
788 }
789
790
791
792
793
794
795 private class NodeIterator extends PathIterator
796 {
797 public NodeIterator()
798 {
799 super(null);
800 _currIterator = _root.entrySet().iterator();
801 _value = (getCollectionModel() == null || isEmpty()) ? null : nextItem();
802 }
803
804 protected Object nextItem()
805 {
806 Object nextKey = null;
807
808 while(((nextKey = _nextEntry()) == null) && _iteratorStack.size() > 0)
809 if(_currPath == null)
810 _currIterator = _iteratorStack.pop();
811 return nextKey;
812 }
813
814 private Object _nextEntry()
815 {
816 Object nextKey = null;
817 if(_currPath != null)
818 {
819 nextKey = nextModelKey(_minDepth);
820 if(nextKey == null)
821 {
822 _currPath = null;
823
824
825
826 if(_iteratorStack.size() > 0)
827 _currIterator = _iteratorStack.pop();
828 _nextEntry();
829 }
830 }
831 else
832 {
833 Map.Entry<Object, Node<Object>> nextNode;
834 while(nextKey == null && _currIterator.hasNext())
835 {
836 nextNode = _currIterator.next();
837 if(_isContained(nextNode.getKey()))
838 nextKey = nextNode.getKey();
839
840
841
842 if(!nextNode.getValue().isEmpty())
843 {
844 _iteratorStack.push(_currIterator);
845 _currIterator = nextNode.getValue().entrySet().iterator();
846 }
847
848 if(nextNode.getValue().isDefaultContained)
849 {
850 _currPath = nextNode.getKey();
851 TreeModel model = getCollectionModel();
852 Object oldPath = model.getRowKey();
853 model.setRowKey(_currPath);
854 _minDepth = model.getDepth() + 1;
855 model.setRowKey(oldPath);
856 return nextKey;
857 }
858 }
859 }
860 return nextKey;
861 }
862
863 private Stack<Iterator <Map.Entry<Object, Node<Object>>>> _iteratorStack =
864 new Stack<Iterator <Map.Entry<Object, Node<Object>>>>();
865 private Iterator <Map.Entry<Object, Node<Object>>> _currIterator;
866 private int _minDepth;
867 }
868
869 private Node<Object> _root;
870 private transient TreeModel _model = null;
871 private static final long serialVersionUID = 1L;
872 private static final TrinidadLogger _LOG =
873 TrinidadLogger.createTrinidadLogger(RowKeySetTreeImpl.class);
874 }