Source Code Cross Referenced for TreeList.java in  » Database-ORM » MMBase » org » mmbase » bridge » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » MMBase » org.mmbase.bridge.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:        This software is OSI Certified Open Source Software.
004:        OSI Certified is a certification mark of the Open Source Initiative.
005:
006:        The license (Mozilla version 1.0) can be read at the MMBase site.
007:        See http://www.MMBase.org/license
008:
009:         */
010:
011:        package org.mmbase.bridge.util;
012:
013:        import org.mmbase.bridge.*;
014:        import org.mmbase.storage.search.*;
015:        import org.mmbase.util.logging.*;
016:
017:        import java.util.*;
018:
019:        /**
020:         * Queries a Tree from MMBase. A Tree is presented as a List of MultiLevel results (ClusterNodes),
021:         * combined with a smart iterator which iterates through the elements of these lists as if it was one
022:         * list ordered as a Tree.
023:         *
024:         *
025:         * @author  Michiel Meeuwissen
026:         * @version $Id: TreeList.java,v 1.30 2008/02/28 12:23:51 michiel Exp $
027:         * @since   MMBase-1.7
028:         */
029:
030:        public class TreeList extends AbstractSequentialBridgeList<Node>
031:                implements  NodeList {
032:            private static final Logger log = Logging
033:                    .getLoggerInstance(TreeList.class);
034:
035:            public static final String REAL_NODES = "realnodes";
036:
037:            protected Cloud cloud;
038:            protected final List<Branch> branches = new ArrayList<Branch>();
039:
040:            protected int topQuery = 0;
041:            protected int numberOfSteps;
042:            private int size;
043:            private boolean needsSizeCheck = true;
044:
045:            protected boolean foundEnd = false;
046:            protected int leafConstraintOffset = Integer.MAX_VALUE;
047:
048:            /**
049:             * @since MMBase-1.8.1
050:             */
051:            protected int max = SearchQuery.DEFAULT_MAX_NUMBER;
052:
053:            /**
054:             * @param q              The 'base' query defining the minimal depth of the tree elements. The trunk of the tree.
055:             */
056:
057:            public TreeList(NodeQuery q) {
058:
059:                if (q.getOffset() > 0) {
060:                    throw new UnsupportedOperationException(
061:                            "Don't know how to implement that");
062:                }
063:                cloud = q.getCloud();
064:                branches.add(new Branch(q));
065:                numberOfSteps = q.getSteps().size();
066:
067:            }
068:
069:            /**
070:             * Copy-constructor
071:             * @since MMBase-1.8
072:             */
073:            public TreeList(TreeList tl) {
074:                cloud = tl.cloud;
075:                Iterator<Branch> i = tl.branches.iterator();
076:                while (i.hasNext()) {
077:                    Branch b = i.next();
078:                    branches.add(new Branch(b));
079:                }
080:                topQuery = tl.topQuery;
081:                numberOfSteps = tl.numberOfSteps;
082:                size = tl.size;
083:                needsSizeCheck = tl.needsSizeCheck;
084:                foundEnd = tl.foundEnd;
085:                leafConstraintOffset = tl.leafConstraintOffset;
086:            }
087:
088:            /**
089:             * @since MMBase-1.8.1
090:             */
091:            public void setMax(int m) {
092:                max = m;
093:            }
094:
095:            /**
096:             * @since MMBase-1.8.1
097:             */
098:            public int getMax() {
099:                return max;
100:            }
101:
102:            /**
103:             * @since MMBase-1.8
104:             */
105:            public Cloud getCloud() {
106:                return cloud;
107:            }
108:
109:            // javadoc inherited
110:            @Override
111:            public int size() {
112:                sizeCheck();
113:                return max != SearchQuery.DEFAULT_MAX_NUMBER ? (max < size ? max
114:                        : size)
115:                        : size;
116:            }
117:
118:            /**
119:             * Checks if the size of the List needs to be (re)determined, and if not, does so. After growing
120:             * a List the size needs recalculation.
121:             * @since MMBase-1.7.1
122:             */
123:            protected void sizeCheck() {
124:                if (needsSizeCheck) {
125:                    int count;
126:                    Branch branch = branches.get(topQuery);
127:                    if (branch.leafResult != null) { // not quite sure that this can hapen
128:                        count = branch.leafResult.size();
129:                    } else {
130:                        NodeQuery newQuery = branch.getLeafQuery();
131:                        count = Queries.count(newQuery);
132:                    }
133:
134:                    if (count == 0) {
135:                        foundEnd = branch.leafConstraint == null
136:                                || Queries.count(branch.getQuery()) == 0;
137:                    }
138:                    size += count;
139:                    needsSizeCheck = false;
140:                }
141:            }
142:
143:            /**
144:             * Grows branches of the Tree, which means that one new query will be created which is one
145:             * relationStep longer than the longest one until now.
146:             * This new relationStep is returned, which can be used to create new constraints.
147:             *
148:             * @return <code>null</code> if no relationstep is added because that would not increase the number of results.
149:             */
150:
151:            public RelationStep grow(NodeManager nodeManager, String role,
152:                    String searchDir) {
153:                sizeCheck();
154:                if (foundEnd) {
155:                    return null;
156:                }
157:                needsSizeCheck = true;
158:
159:                NodeQuery lastQuery = branches.get(topQuery).getQuery();
160:                NodeQuery newQuery = (NodeQuery) lastQuery.cloneWithoutFields();
161:
162:                // add relations step
163:                RelationStep step = newQuery.addRelationStep(nodeManager, role,
164:                        searchDir);
165:                Step nextStep = step.getNext();
166:
167:                // make sure every step has a unique alias
168:                newQuery.setAlias(step, step.getTableName()
169:                        + (numberOfSteps - 1));
170:                newQuery.setAlias(nextStep, nodeManager.getName()
171:                        + numberOfSteps);
172:
173:                // new number of steps
174:                numberOfSteps = newQuery.getSteps().size();
175:
176:                // the new step must be the 'node' step
177:                newQuery.setNodeStep(nextStep);
178:
179:                branches.add(new Branch(newQuery));
180:                topQuery++;
181:
182:                return step;
183:            }
184:
185:            /**
186:             * Returns the top most query, associated with the last call to {@link #grow}.
187:             * @since MMBase-1.8
188:             */
189:            public NodeQuery getLeafQuery() {
190:                return branches.get(topQuery).getQuery();
191:            }
192:
193:            /**
194:             * Sets a 'leaf constraint' on the last 'growed' step. A leaf constraint is a constraint which is only
195:             * used on leafs, so if the tree is grown further, the leaf constraint will not be passed to the branches.
196:             * @since MMBase-1.8
197:             */
198:            public void setLeafConstraint(Constraint constraint) {
199:
200:                Branch branch = branches.get(topQuery);
201:                if (branch.result != null) {
202:                    throw new IllegalStateException("The query for branch "
203:                            + topQuery + " was already executed");
204:                }
205:                if (topQuery < leafConstraintOffset) {
206:                    leafConstraintOffset = topQuery;
207:                }
208:                leafConstraintOffset = 0;
209:                branch.leafConstraint = constraint;
210:
211:            }
212:
213:            /**
214:             * Executes one query if that did not happen yet, and stores the result in the 'results' List
215:             * @return NodeList or <code>null</code> if queryNumber too big
216:             * @throws IndexOutOfBoundsException if queryNumber < 0
217:             */
218:            protected NodeList getList(int queryNumber) {
219:                if (queryNumber < 0) {
220:                    throw new IndexOutOfBoundsException("No query for '"
221:                            + queryNumber + "'");
222:                }
223:
224:                if (queryNumber >= branches.size()) {
225:                    return null;
226:                }
227:
228:                Branch branch = branches.get(queryNumber);
229:                if (branch.result == null) {
230:                    NodeQuery query = branch.getQuery();
231:                    branch.result = cloud.getList(query);
232:                    if (branch.leafConstraint == null) {
233:                        branch.leafResult = branch.result;
234:                    }
235:                }
236:                return branch.result;
237:            }
238:
239:            /**
240:             * Executes one query as a 'leaf' query.
241:             * @since MMBase-1.8
242:             */
243:            protected NodeList getLeafList(int queryNumber) {
244:                if (queryNumber < 0) {
245:                    throw new IndexOutOfBoundsException("No query for '"
246:                            + queryNumber + "'");
247:                }
248:
249:                if (queryNumber >= branches.size()) {
250:                    return null;
251:                }
252:
253:                Branch branch = branches.get(queryNumber);
254:                if (branch.leafResult == null) {
255:                    NodeQuery query = branch.getLeafQuery();
256:                    branch.leafResult = cloud.getList(query);
257:                    branch.leafResult.setProperty(REAL_NODES, null);
258:                    if (branch.leafConstraint == null) {
259:                        branch.result = branch.leafResult;
260:                    }
261:                }
262:                return branch.leafResult;
263:            }
264:
265:            // javadoc inherited
266:            @Override
267:            public ListIterator<Node> listIterator(int ind) {
268:                return treeIterator(ind);
269:            }
270:
271:            public NodeIterator nodeIterator() {
272:                return treeIterator(0);
273:            }
274:
275:            public TreeIterator treeIterator() {
276:                return treeIterator(0);
277:            }
278:
279:            protected TreeIterator treeIterator(int ind) {
280:                return new TreeItr(ind);
281:            }
282:
283:            // javadoc inherited
284:            public Node getNode(int i) {
285:                return get(i);
286:            }
287:
288:            /**
289:             * Returns node 'index' of query result 'queryIndex' as a 'real' node (so not a cluster node)
290:             */
291:            protected Node getRealNode(int queryIndex, int index) {
292:                NodeList nodeList = getLeafList(queryIndex);
293:                NodeList realNodes = (NodeList) nodeList
294:                        .getProperty(REAL_NODES);
295:                if (realNodes == null || realNodes.size() != nodeList.size()) {
296:                    Branch branch = branches.get(queryIndex);
297:                    NodeQuery nq = branch.getLeafQuery();
298:                    realNodes = nq.getNodeManager().getList(nq); // We trust the query cache! (the query is performed already, but on Cloud)
299:                    nodeList.setProperty(REAL_NODES, realNodes);
300:                }
301:                assert realNodes.size() == nodeList.size() : "The size of nodeList "
302:                        + nodeList.size()
303:                        + " does not match realNodes "
304:                        + realNodes.size()
305:                        + " at queryIndex; "
306:                        + queryIndex
307:                        + " query "
308:                        + branches.get(queryIndex).getLeafQuery().toSql();
309:                assert realNodes.size() >= index : "The size of realNodes  ("
310:                        + realNodes.size() + ") is too small (index = " + index
311:                        + ")";
312:                return realNodes.getNode(index);
313:            }
314:
315:            public NodeList subNodeList(int start, int end) {
316:                throw new UnsupportedOperationException(
317:                        "SubNodeLists not implemented for TreeList");
318:            }
319:
320:            public NodeList subList(int start, int end) {
321:                throw new UnsupportedOperationException(
322:                        "SubNodeLists not implemented for TreeList");
323:            }
324:
325:            @Override
326:            public String toString() {
327:                int size = size();
328:                return "size: " + size + " " + branches.toString();
329:            }
330:
331:            /**
332:             * Structure to hold the information for every branch-depth.
333:             * @since MMBase-1.8
334:             */
335:            protected class Branch {
336:                final private NodeQuery query;
337:                private NodeQuery leafQuery = null;
338:                NodeList result = null;
339:                NodeList leafResult = null;
340:                Constraint leafConstraint = null;
341:
342:                Branch(NodeQuery q) {
343:                    query = q;
344:                }
345:
346:                Branch(Branch b) {
347:                    query = (NodeQuery) b.query.clone();
348:                    result = b.result;
349:                    leafQuery = b.leafQuery == null ? null
350:                            : (NodeQuery) b.leafQuery.clone();
351:                    leafResult = null;
352:                    leafConstraint = b.leafConstraint;
353:                }
354:
355:                NodeQuery getQuery() {
356:                    return query;
357:                }
358:
359:                NodeQuery getLeafQuery() {
360:                    if (leafQuery != null)
361:                        return leafQuery;
362:                    Queries.sortUniquely(query);
363:                    Queries.addSortedFields(query);
364:                    int m = TreeList.this .getMax();
365:                    if (m != SearchQuery.DEFAULT_MAX_NUMBER) {
366:                        int cm = query.getMaxNumber();
367:                        if (cm == -1 || m < cm) {
368:                            query.setMaxNumber(m);
369:                        }
370:                    }
371:                    query.markUsed();
372:                    if (leafConstraint != null) {
373:                        leafQuery = (NodeQuery) query.clone();
374:                        Queries.addConstraint(leafQuery, leafConstraint);
375:                        leafQuery.markUsed();
376:                    } else {
377:                        leafQuery = query;
378:                    }
379:                    return leafQuery;
380:                }
381:
382:                @Override
383:                public String toString() {
384:                    return query.toString()
385:                            + (leafConstraint != null ? "[" + leafConstraint
386:                                    + "]" : "");
387:                }
388:
389:            }
390:
391:            /**
392:             * The TreeIterator contains the core-functionality of TreeList.
393:             */
394:            protected class TreeItr implements  TreeIterator {
395:
396:                private List<NodeIterator> nodeIterators = new ArrayList<NodeIterator>(); // an iterator for each query result
397:                private NodeList nextNodes = TreeList.this .cloud
398:                        .createNodeList();
399:                // contains 'next' nodes for each query result (needed for 'next()')
400:
401:                private NodeList previousNodes = TreeList.this .cloud
402:                        .createNodeList();
403:                // contains 'previous' nodes for each query result (needed for 'previous()')
404:
405:                private int currentIterator; // number of current iterator which is iterated
406:                private int nextIndex; // the next index number, so this is 0 on the beginning, and <size> just before the last next()
407:
408:                private boolean encounteredLeafConstraint = false;
409:                private Node current;
410:
411:                TreeItr(int i) {
412:                    if (i < 0 || (i > 0 && i > TreeList.this .size())) {
413:                        throw new IndexOutOfBoundsException("Index: " + i
414:                                + ", Size: " + TreeList.this .size());
415:                    }
416:                    currentIterator = 0;
417:                    nextIndex = 0;
418:                    while (nextIndex < i) {
419:                        next(); // fast forward to requested start index.
420:                    }
421:
422:                }
423:
424:                public boolean hasNext() {
425:                    if (TreeList.this .max != SearchQuery.DEFAULT_MAX_NUMBER
426:                            && nextIndex > TreeList.this .max)
427:                        return false;
428:                    if (TreeList.this .foundEnd) { // why bother
429:                        return nextIndex < TreeList.this .size();
430:                    } else {
431:                        int i = 0;
432:                        while (prepare(i)) {
433:                            NodeIterator iterator = nodeIterators.get(i);
434:                            Node nextNode = nextNodes.get(i);
435:                            if (nextNode != null) {
436:                                return true;
437:                            } else {
438:                                i++;
439:                            }
440:                        }
441:                        return false;
442:                    }
443:                }
444:
445:                /**
446:                 * Makes sure that query with given index has an iterator, a 'next' node and a 'previous' node.
447:                 * @return true it such  query existed, false, otherwise
448:                 */
449:                protected final boolean prepare(int index) {
450:                    for (int i = nodeIterators.size(); i <= index; i++) {
451:                        NodeList nl = TreeList.this .getLeafList(i);
452:                        if (TreeList.this .leafConstraintOffset <= i) {
453:                            encounteredLeafConstraint = true;
454:                        }
455:                        NodeIterator iterator = null;
456:                        if (nl != null) {
457:                            iterator = nl.nodeIterator();
458:                        }
459:                        nodeIterators.add(iterator);
460:                        previousNodes.add(null); // just prepared iterator never has a previous node already
461:                        if (iterator == null) {
462:                            nextNodes.add(null);
463:                            return false;
464:                        } else {
465:                            if (iterator.hasNext()) {
466:                                nextNodes.add(iterator.nextNode());
467:                            } else {
468:                                nextNodes.add(null);
469:                                return true;
470:                            }
471:                        }
472:                    }
473:                    return true;
474:                }
475:
476:                /**
477:                 * Uses the new 'next' node of the iterator with the given index.
478:                 * This means that it becomes the previous node and that a new 'next' node will be determined
479:                 */
480:                protected final void useNext(int index) {
481:                    Node node = nextNodes.getNode(index);
482:                    if (node == null)
483:                        throw new NoSuchElementException("No such element "
484:                                + index + " in " + nextNodes);
485:                    previousNodes.set(index, node);
486:                    NodeIterator iterator = nodeIterators.get(index);
487:                    if (iterator.hasNext()) {
488:                        Node nextNode = iterator.nextNode();
489:                        nextNodes.set(index, nextNode);
490:                    } else {
491:                        nextNodes.set(index, null);
492:                    }
493:                }
494:
495:                /**
496:                 * Returns the 'real' node, thus the just used 'next' node of index.
497:                 */
498:                protected final Node getRealNode(int index) {
499:                    ListIterator<Node> iterator = nodeIterators.get(index);
500:                    return TreeList.this .getRealNode(index, iterator
501:                            .previousIndex());
502:                }
503:
504:                public Node nextNode() {
505:                    nextIndex++;
506:                    current = getNextNode();
507:                    return current;
508:                }
509:
510:                public Node getParent() {
511:                    NodeList nl = TreeList.this .getLeafList(currentDepth() - 1);
512:                    Query q = TreeList.this .branches.get(currentDepth() - 1)
513:                            .getQuery();
514:                    List<Step> steps = q.getSteps();
515:                    if (steps.size() >= 3) {
516:                        Step this Step = steps.get(steps.size() - 1);
517:                        Step parentStep = steps.get(steps.size() - 3);
518:                        for (Node sibling : nl) {
519:                            if (current.getNumber() == sibling
520:                                    .getIntValue(this Step.getAlias()
521:                                            + ".number")) {
522:                                return getCloud().getNode(
523:                                        sibling.getIntValue(parentStep
524:                                                .getAlias()
525:                                                + ".number"));
526:                            }
527:                        }
528:                    }
529:                    return null;
530:                }
531:
532:                public NodeList getSiblings() {
533:                    NodeList nl = TreeList.this .getLeafList(currentDepth() - 1);
534:                    Query q = TreeList.this .branches.get(currentDepth() - 1)
535:                            .getQuery();
536:                    List<Step> steps = q.getSteps();
537:                    NodeList l = getCloud().createNodeList();
538:                    if (steps.size() >= 3) {
539:                        int start = 0;
540:                        int end = 0;
541:                        int parent = getParent().getNumber();
542:                        Step this Step = steps.get(steps.size() - 1);
543:                        Step parentStep = steps.get(steps.size() - 3);
544:                        for (Node sibling : nl) {
545:                            if (sibling.getIntValue(parentStep.getAlias()
546:                                    + ".number") == parent) {
547:                                l.add(getCloud().getNode(
548:                                        sibling.getIntValue(this Step.getAlias()
549:                                                + ".number")));
550:                            }
551:                        }
552:                        return l;
553:                    } else {
554:                        l.add(current);
555:                        return l;
556:                    }
557:                }
558:
559:                /**
560:                 * Depth of the last node fetched with next() or nextNode()
561:                 */
562:                public int currentDepth() {
563:                    Branch branch = TreeList.this .branches.get(currentIterator);
564:                    int depth = (branch.query.getSteps().size() + 1) / 2;
565:                    if (nextIndex == 0) {
566:                        return depth - 1;
567:                    } else {
568:                        return depth;
569:                    }
570:                }
571:
572:                public Node next() {
573:                    return nextNode();
574:                }
575:
576:                /**
577:                 *
578:                 * Implementation idea graphicly.
579:                 <pre>
580:                                iterators
581:
582:
583:                      current-2  current-1  current       current+1                         [///]: used node
584:                       [///]       [///]     [///]         [///]                            [|||]: last used node (lastNode)
585:                                                                                            [   ]: unused node
586:                 ...   [///]       [///]     [|||] _       [///]    previousNodes           [ * ]: considered next node (nextListNextNode)
587:                                                    \
588:                       [   ]       [   ]     [   ]   `---> [ * ]    nextNodes
589:
590:                       if (! [|||] contained by [ * ]) current--
591:                 </pre>
592:
593:                 Every time next is called, the last used node is compared with the next node of the
594:                 next iterator (the arrow in the above scheme). If the last used node is 'contained' by
595:                 this next node, then this next node of the next iterator will be 'next()' otherwise current
596:                 is decreased by one and next is called recursively. This means that the next node is always
597:                 one longer than the current one, equally long, or shorter.
598:
599:                 If 'leaf constraints' are in use, then the implementation jumps to getNextLeafNode, which simply returns the 'smallest node' of all iterators.
600:                 */
601:                protected final Node getNextNode() {
602:                    prepare(currentIterator);
603:                    if (encounteredLeafConstraint) {
604:                        return getNextLeafNode();
605:                    }
606:
607:                    final Branch currentBranch = TreeList.this .branches
608:                            .get(currentIterator);
609:
610:                    Node previousNode = previousNodes.getNode(currentIterator);
611:                    if (previousNode == null) { // first of iterator
612:                        Node node = getRealNode(currentIterator);
613:                        useNext(currentIterator);
614:                        return node;
615:                    }
616:
617:                    Node nextListNextNode = prepare(currentIterator + 1) ? nextNodes
618:                            .getNode(currentIterator + 1)
619:                            : null;
620:
621:                    if (nextListNextNode == null) {
622:                        if (currentIterator > 0) {
623:                            currentIterator--;
624:                            return getNextNode();
625:                        } else {
626:                            Node node = getRealNode(0);
627:                            useNext(0);
628:                            return node;
629:                        }
630:                    }
631:
632:                    List<SortOrder> sortOrders = currentBranch.getQuery()
633:                            .getSortOrders();
634:                    final boolean contains = Queries.compare(previousNode,
635:                            nextListNextNode, sortOrders) >= 0;
636:
637:                    if (log.isDebugEnabled()) {
638:                        log.debug("comparing " + previousNode + " with "
639:                                + nextListNextNode);
640:                    }
641:
642:                    if (contains) {
643:                        currentIterator++;
644:                        Node node = getRealNode(currentIterator);
645:                        useNext(currentIterator);
646:                        return node;
647:                    } else {
648:                        if (currentIterator > 0) {
649:                            currentIterator--;
650:                            return getNextNode();
651:                        } else {
652:                            Node node = getRealNode(0);
653:                            useNext(0);
654:                            return node;
655:                        }
656:                    }
657:                }
658:
659:                /**
660:                 * Simply returns the 'smallest' of all available nodes (compared to the 'previous node')
661:                 * This is actually an alternavite implementation for getNextNode, but it also works when
662:                 * 'leaf' constraints are applied.
663:                 * @since MMBase-1.8
664:                 */
665:                protected final Node getNextLeafNode() {
666:                    Node smallestAvailableNode = null;
667:                    List<SortOrder> smallestSortOrders = null; // Sort-Orders list of smallest availabe node.
668:                    int i = -1;
669:
670:                    while (prepare(++i)) {
671:                        Node candidate = i < nextNodes.size() ? nextNodes
672:                                .getNode(i) : null;
673:                        if (candidate == null) {
674:                            continue;
675:                        }
676:                        Branch branch = TreeList.this .branches.get(i);
677:                        List<SortOrder> sortOrders = branch.getLeafQuery()
678:                                .getSortOrders();
679:                        if (smallestAvailableNode == null) {
680:                            smallestAvailableNode = candidate;
681:                            smallestSortOrders = sortOrders;
682:                            currentIterator = i;
683:                        } else {
684:                            List<SortOrder> compareSortOrders = sortOrders
685:                                    .size() < smallestSortOrders.size() ? sortOrders
686:                                    : smallestSortOrders;
687:                            int compare = Queries.compare(candidate,
688:                                    smallestAvailableNode, compareSortOrders);
689:                            if (compare < 0) {
690:                                smallestAvailableNode = candidate;
691:                                smallestSortOrders = sortOrders;
692:                                currentIterator = i;
693:                            }
694:                        }
695:                    }
696:                    if (smallestAvailableNode == null) {
697:                        throw new NoSuchElementException();
698:                    }
699:                    Node node = getRealNode(currentIterator);
700:                    useNext(currentIterator);
701:                    return node;
702:                }
703:
704:                public boolean hasPrevious() {
705:                    return nextIndex > 0;
706:                }
707:
708:                public Node previousNode() {
709:                    nextIndex--;
710:                    throw new UnsupportedOperationException("unfinished");
711:                }
712:
713:                public Node previous() {
714:                    return previousNode();
715:                }
716:
717:                public int nextIndex() {
718:                    return nextIndex;
719:                }
720:
721:                public int previousIndex() {
722:                    return nextIndex - 1;
723:                }
724:
725:                public void remove() {
726:                    throw new UnsupportedOperationException(
727:                            "TreeList is not modifiable");
728:                }
729:
730:                public void set(Node o) {
731:                    throw new UnsupportedOperationException(
732:                            "TreeList is not modifiable");
733:                }
734:
735:                public void add(Node o) {
736:                    throw new UnsupportedOperationException(
737:                            "TreeList is not modifiable");
738:                }
739:
740:            }
741:
742:            /**
743:             * For testing only. Based on RMMCI,
744:             * please use the System property to specify de cloud context
745:             * -Dmmbase.defaultcloudcontext=rmi://localhost:1111/remotecontext
746:             * @param args the start node (in one argument)
747:             */
748:
749:            protected static NodeQuery getQuery(String[] args) {
750:                if (args.length == 0) {
751:                    System.err
752:                            .println("Usage: java -Dmmbase.defaultcloudcontext=rmi://localhost:1111/remotecontext "
753:                                    + TreeList.class.getName() + " <startnode>");
754:                    System.exit(1);
755:                }
756:
757:                String startNodes = args[0];
758:                Cloud cloud = ContextProvider.getDefaultCloudContext()
759:                        .getCloud("mmbase");
760:
761:                String type = args.length > 1 ? args[1] : "segments";
762:                String role = args.length > 2 ? args[2] : "index";
763:                NodeManager object = cloud.getNodeManager(type);
764:
765:                NodeQuery q = cloud.createNodeQuery();
766:                Step step = q.addStep(object);
767:                q.setNodeStep(step);
768:                RelationStep relationStep = q.addRelationStep(object, role,
769:                        "destination");
770:                q.setNodeStep(relationStep.getNext());
771:                StepField pos = q.createStepField(relationStep, "pos");
772:                q.addSortOrder(pos, SortOrder.ORDER_ASCENDING);
773:
774:                object.getList(q);
775:
776:                Queries.addStartNodes(q, startNodes);
777:                return q;
778:            }
779:
780:            public static void doTest(java.io.Writer writer, NodeQuery q) {
781:                Cloud cloud = q.getCloud();
782:
783:                NodeManager object = q.getNodeManager();
784:                try {
785:                    //String text = "%potjandosie%";
786:                    String text = "%%";
787:
788:                    long startTime = System.currentTimeMillis();
789:
790:                    TreeList tree = new TreeList(q);
791:                    if (object.hasField("body")) {
792:                        Constraint con2 = Queries.createConstraint(tree
793:                                .getLeafQuery(), "body", Queries
794:                                .getOperator("LIKE"), text);
795:                        //tree.setLeafConstraint(con2);
796:                    }
797:
798:                    writer.write("grow1:\n");
799:                    writer.flush();
800:                    RelationStep step = tree.grow(object, "posrel",
801:                            "destination");
802:                    NodeQuery top = tree.getLeafQuery();
803:                    if (object.hasField("body")) {
804:                        Constraint con1 = Queries.createConstraint(top, "body",
805:                                Queries.getOperator("LIKE"), text);
806:                        //tree.setLeafConstraint(con1);
807:                    }
808:                    assert step != null;
809:                    StepField pos = top.createStepField(step, "pos");
810:                    top.addSortOrder(pos, SortOrder.ORDER_ASCENDING);
811:
812:                    writer.write("top " + top.toSql() + " grow2:\n");
813:                    writer.flush();
814:                    tree.grow(object, "posrel", "destination");
815:                    NodeQuery leaf = tree.getLeafQuery();
816:                    Constraint con = Queries.createConstraint(leaf, "body",
817:                            Queries.getOperator("LIKE"), text);
818:                    //tree.setLeafConstraint(con);
819:
820:                    writer
821:                            .write("GROWN, now using ================================================================================");
822:                    writer.flush();
823:                    TreeIterator i = tree.treeIterator();
824:                    writer.write("initial depth " + i.currentDepth() + "\n");
825:                    writer.flush();
826:                    writer.write("size: " + tree.size() + "\n");
827:                    writer.flush();
828:                    while (i.hasNext()) {
829:                        Node n = i.next();
830:                        try {
831:                            writer.write(n.getFunctionValue("index", null)
832:                                    .toString()
833:                                    + "\t");
834:                        } catch (Exception e) {
835:                        }
836:                        writer.write(i.currentDepth() + "  " + n.getNumber()
837:                                + " " + n.getFunctionValue("gui", null) + "\n");
838:                        writer.flush();
839:                    }
840:                    writer.write("size: " + tree.size() + "\n");
841:                    writer.write("duration: "
842:                            + (System.currentTimeMillis() - startTime)
843:                            + " ms\n");
844:                    writer.write("finish depth: " + i.currentDepth());
845:                    writer.flush();
846:                } catch (Exception e) {
847:                    System.err.println(e.getClass().getName() + e.getMessage()
848:                            + Logging.stackTrace(e));
849:                }
850:
851:            }
852:
853:            public static void main(String[] args) {
854:                NodeQuery q = getQuery(args);
855:                doTest(new java.io.OutputStreamWriter(System.out), q);
856:
857:            }
858:
859:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.