001: /*
002: * Jalisto - JAva LIght STOrage
003: * Copyright (C) 2000-2005 Xcalia http://www.xcalia.com
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
018: *
019: * Xcalia
020: * 71, rue Desnouettes
021: * 75014 Paris - France
022: * http://www.xcalia.com
023: */
024: package org.objectweb.jalisto.se.query.execution;
025:
026: import org.objectweb.jalisto.se.impl.LogicalOid;
027: import org.objectweb.jalisto.se.api.Session;
028: import org.objectweb.jalisto.se.api.MetaRepository;
029: import org.objectweb.jalisto.se.api.query.IndexManager;
030: import org.objectweb.jalisto.se.api.query.Constraint;
031: import org.objectweb.jalisto.se.api.internal.SessionInternal;
032: import org.objectweb.jalisto.se.api.internal.InternalMetaRepository;
033: import org.objectweb.jalisto.se.query.constraint.*;
034: import org.objectweb.jalisto.se.query.result.QueryResultWrapper;
035: import org.objectweb.jalisto.se.query.result.WrapperSet;
036:
037: import java.util.*;
038:
039: public class ExecutionTree {
040:
041: public ExecutionTree(Constraint rootConstraint,
042: MetaRepository repository, String className) {
043: toResolveAndNodes = new ArrayList();
044:
045: readedValues = new HashMap();
046: leafs = new HashSet();
047:
048: this .baseClassName = className;
049:
050: root = buildElement(null, rootConstraint, 0);
051: toResolveAndNodesBackup = new ArrayList(toResolveAndNodes);
052: root.defineMeta(repository);
053: }
054:
055: public ExecutionElement buildElement(ExecutionElement father,
056: Constraint constraint, int depth) {
057: ExecutionElement element = null;
058: if (constraint instanceof BinaryBooleanOperatorConstraint) {
059: BinaryBooleanOperatorConstraint binConstraint = (BinaryBooleanOperatorConstraint) constraint;
060: ExecutionNode node = new ExecutionNode(this , father,
061: binConstraint, depth);
062: node.setLeft(buildElement(node, binConstraint.getLeft(),
063: depth + 1));
064: node.setRight(buildElement(node, binConstraint.getRight(),
065: depth + 1));
066: if (binConstraint.isAndOperator()) {
067: toResolveAndNodes.add(node);
068: }
069: element = node;
070: } else if (constraint instanceof ValueConstraintImpl) {
071: element = new ValueExecutionLeaf(this , father,
072: (ValueConstraintImpl) constraint, depth);
073: leafs.add(element);
074: } else if (constraint instanceof SubQueryConstraintImpl) {
075: element = new SubQueryExecutionLeaf(this , father,
076: (SubQueryConstraintImpl) constraint, depth);
077: leafs.add(element);
078: }
079: return element;
080: }
081:
082: public Collection getToResolveAndNodes() {
083: return toResolveAndNodes;
084: }
085:
086: public Set getLeafs() {
087: return leafs;
088: }
089:
090: public Map getReadedValues() {
091: return readedValues;
092: }
093:
094: public void cleanLeaf() {
095: root.cleanAll();
096: readedValues.clear();
097: toResolveAndNodes.clear();
098: toResolveAndNodes.addAll(toResolveAndNodesBackup);
099: }
100:
101: /**
102: * ******************************* RESOLVE ***************************************
103: */
104:
105: public Set resolve(SessionInternal session,
106: IndexManager indexManager) {
107: if (manageIndexes(session, indexManager)) {
108: resolveWithIndex(session);
109: }
110: if (root.isResolved()) {
111: return root.getResolvedValues().getCopyInSet();
112: }
113: return resolveOnElements(session);
114: }
115:
116: public Set resolveOnElements(SessionInternal session) {
117: Iterator extent = session.getExtent(baseClassName).readFully()
118: .iterator();
119: Set result = new HashSet();
120: while (extent.hasNext()) {
121: LogicalOid floid = (LogicalOid) extent.next();
122: Object[] values = (Object[]) readedValues.get(floid);
123: if (values == null) {
124: values = session.readObjectByOid(floid, true);
125: readedValues.put(floid, values);
126: }
127: QueryResultWrapper wrapper = new QueryResultWrapper(floid,
128: values);
129: if (root.resolveOnElement(session, wrapper)) {
130: result.add(wrapper);
131: }
132: }
133: return result;
134: }
135:
136: public boolean resolveOnOneElement(SessionInternal session,
137: QueryResultWrapper wrapper) {
138: return root.resolveOnElement(session, wrapper);
139: }
140:
141: private boolean manageIndexes(Session session,
142: IndexManager indexManager) {
143: boolean useIndexes = false;
144: Set toResolveBack = new HashSet();
145: Iterator leafIterator = leafs.iterator();
146: while (leafIterator.hasNext()) {
147: ExecutionElement leaf = (ExecutionElement) leafIterator
148: .next();
149: leaf.resolveLeafOnIndex(session, indexManager);
150: if (leaf.isResolved()) {
151: ExecutionElement resBack = leaf.resolveBack();
152: if (resBack != null) {
153: toResolveBack.add(resBack);
154: }
155: }
156: }
157:
158: Set toResolveBackNext = new HashSet();
159: while (!toResolveBack.isEmpty()) {
160: useIndexes = true;
161: Iterator it = toResolveBack.iterator();
162: while (it.hasNext()) {
163: ExecutionElement element = (ExecutionElement) it.next();
164: ExecutionNode node = element.resolveBack();
165: if (node != null) {
166: toResolveBackNext.add(node);
167: }
168: }
169: toResolveBack.clear();
170: toResolveBack.addAll(toResolveBackNext);
171: toResolveBackNext.clear();
172: }
173:
174: return useIndexes;
175: }
176:
177: private void resolveWithIndex(SessionInternal session) {
178: if (root.isResolved()) {
179: return;
180: }
181:
182: LinkedList toResolve = new LinkedList();
183: Iterator ands = toResolveAndNodes.iterator();
184: while (ands.hasNext()) {
185: ExecutionElement e = (ExecutionElement) ands.next();
186: if (e.onlyOneToResolve()) {
187: toResolve.add(e);
188: }
189: }
190: Collections.sort(toResolve);
191:
192: while (!toResolve.isEmpty()) {
193: ExecutionNode andNode = (ExecutionNode) toResolve
194: .removeFirst();
195:
196: boolean before = false;
197: while ((andNode.getFather() != null)
198: && (andNode.getFather().isAndNode())
199: && (andNode.getFather().onlyOneToResolve())) {
200: andNode = andNode.getFather();
201: before = true;
202: }
203:
204: if (before) {
205: andNode.resolveBeforeAndNodeNearRoot(session, null,
206: toResolve);
207: } else {
208: andNode
209: .resolveWithCandidates(session,
210: new WrapperSet());
211: }
212:
213: ExecutionElement son = andNode;
214: ExecutionElement father = andNode.resolveBack();
215: while (father != null) {
216: son = father;
217: father = father.resolveBack();
218: }
219:
220: if ((son == root) && root.isResolved) {
221: return;
222: }
223:
224: if (son.isAndNode() && son.onlyOneToResolve()) {
225: toResolve.add(son);
226: Collections.sort(toResolve);
227: }
228: }
229: }
230:
231: public boolean detectOrBranch(IndexManager indexManager) {
232: return root.isInOrBranch(indexManager);
233: }
234:
235: private ArrayList toResolveAndNodes;
236: private ArrayList toResolveAndNodesBackup;
237: private Set leafs;
238: private ExecutionElement root;
239: private String baseClassName;
240: private Map readedValues;
241: }
|