KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > db4o > QQueryBase


1 /* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com
2
3 This file is part of the db4o open source object database.
4
5 db4o is free software; you can redistribute it and/or modify it under
6 the terms of version 2 of the GNU General Public License as published
7 by the Free Software Foundation and as clarified by db4objects' GPL
8 interpretation policy, available at
9 http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
10 Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
11 Suite 350, San Mateo, CA 94403, USA.
12
13 db4o is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

21 package com.db4o;
22
23 import com.db4o.config.*;
24 import com.db4o.foundation.*;
25 import com.db4o.inside.callbacks.Callbacks;
26 import com.db4o.inside.marshall.*;
27 import com.db4o.inside.query.*;
28 import com.db4o.query.*;
29 import com.db4o.reflect.*;
30 import com.db4o.types.*;
31
32 /**
33  * QQuery is the users hook on our graph.
34  *
35  * A QQuery is defined by it's constraints.
36  *
37  * NOTE: This is just a 'partial' base class to allow for variant implementations
38  * in db4oj and db4ojdk1.2. It assumes that itself is an instance of QQuery
39  * and should never be used explicitly.
40  *
41  * @exclude
42  */

43 public abstract class QQueryBase implements Unversioned {
44
45     private static final transient IDGenerator i_orderingGenerator = new IDGenerator();
46
47     transient Transaction i_trans;
48     
49     public Collection4 i_constraints = new Collection4();
50
51     public QQuery i_parent;
52     
53     public String JavaDoc i_field;
54     
55     private transient QueryEvaluationMode _evaluationMode;
56     
57     public int _evaluationModeAsInt;
58     
59     public QueryComparator _comparator;
60     
61     private transient final QQuery _this;
62     
63     protected QQueryBase() {
64         // C/S only
65
_this = cast(this);
66     }
67
68     protected QQueryBase(Transaction a_trans, QQuery a_parent, String JavaDoc a_field) {
69         _this = cast(this);
70         i_trans = a_trans;
71         i_parent = a_parent;
72         i_field = a_field;
73     }
74
75     void addConstraint(QCon a_constraint) {
76         i_constraints.add(a_constraint);
77     }
78
79     private void addConstraint(Collection4 col, Object JavaDoc obj) {
80         if(attachToExistingConstraints(col, obj, true)){
81             return;
82         }
83         if(attachToExistingConstraints(col, obj, false)){
84             return;
85         }
86         QConObject newConstraint = new QConObject(i_trans, null, null, obj);
87         addConstraint(newConstraint);
88         col.add(newConstraint);
89     }
90
91     private boolean attachToExistingConstraints(Collection4 col, Object JavaDoc obj, boolean onlyForPaths) {
92         boolean found = false;
93         Iterator4 j = iterateConstraints();
94         while (j.moveNext()) {
95             QCon existingConstraint = (QCon)j.current();
96             boolean[] removeExisting = { false };
97             if(! onlyForPaths || (existingConstraint instanceof QConPath) ){
98                 QCon newConstraint = existingConstraint.shareParent(obj, removeExisting);
99                 if (newConstraint != null) {
100                     addConstraint(newConstraint);
101                     col.add(newConstraint);
102                     if (removeExisting[0]) {
103                         removeConstraint(existingConstraint);
104                     }
105                     found = true;
106                     if(! onlyForPaths){
107                         return true;
108                     }
109                 }
110             }
111         }
112         return found;
113     }
114
115     /**
116      * Search for slot that corresponds to class. <br>If not found add it.
117      * <br>Constrain it. <br>
118      */

119     public Constraint constrain(Object JavaDoc example) {
120         synchronized (streamLock()) {
121             example = Platform4.getClassForType(example);
122             
123             ReflectClass claxx = reflectClassForClass(example);
124             if (claxx != null) {
125                 return addClassConstraint(claxx);
126             }
127             
128             QConEvaluation eval = Platform4.evaluationCreate(i_trans, example);
129             if (eval != null) {
130                 return addEvaluationToAllConstraints(eval);
131             }
132             
133             Collection4 constraints = new Collection4();
134             addConstraint(constraints, example);
135             return toConstraint(constraints);
136         }
137     }
138
139     private Constraint addEvaluationToAllConstraints(QConEvaluation eval) {
140         Iterator4 i = iterateConstraints();
141         while (i.moveNext()) {
142             ((QCon)i.current()).addConstraint(eval);
143         }
144         // FIXME: should return valid Constraint object
145
return null;
146     }
147
148     private Constraint addClassConstraint(ReflectClass claxx) {
149         if(claxx.equals(stream().i_handlers.ICLASS_OBJECT)){
150             // FIXME: should return valid Constraint object
151
return null;
152         }
153         
154         Collection4 col = new Collection4();
155         if (claxx.isInterface()) {
156             return addInterfaceConstraint(claxx);
157         }
158
159         Iterator4 constraintsIterator = iterateConstraints();
160         while (constraintsIterator.moveNext()) {
161             QCon existingConstraint = (QConObject)constraintsIterator.current();
162             boolean[] removeExisting = { false };
163             QCon newConstraint =
164                 existingConstraint.shareParentForClass(claxx, removeExisting);
165             if (newConstraint != null) {
166                 addConstraint(newConstraint);
167                 col.add(newConstraint);
168                 if (removeExisting[0]) {
169                     removeConstraint(existingConstraint);
170                 }
171             }
172         }
173         if (col.size() == 0) {
174             QConClass qcc = new QConClass(i_trans, null, null, claxx);
175             addConstraint(qcc);
176             return qcc;
177         }
178
179         return toConstraint(col);
180     }
181
182     private Constraint addInterfaceConstraint(ReflectClass claxx) {
183         Collection4 classes = stream().classCollection().forInterface(claxx);
184         if (classes.size() == 0) {
185             QConClass qcc = new QConClass(i_trans, null, null, claxx);
186             addConstraint(qcc);
187             return qcc;
188         }
189         Iterator4 i = classes.iterator();
190         Constraint constr = null;
191         while (i.moveNext()) {
192             YapClass yapClass = (YapClass)i.current();
193             ReflectClass yapClassClaxx = yapClass.classReflector();
194             if(yapClassClaxx != null){
195                 if(! yapClassClaxx.isInterface()){
196                     if(constr == null){
197                         constr = constrain(yapClassClaxx);
198                     }else{
199                         constr = constr.or(constrain(yapClass.classReflector()));
200                     }
201                 }
202             }
203             
204         }
205         return constr;
206     }
207
208     private ReflectClass reflectClassForClass(Object JavaDoc example) {
209         if(example instanceof ReflectClass){
210             return (ReflectClass)example;
211         }
212         if(example instanceof Class JavaDoc) {
213             return i_trans.reflector().forClass((Class JavaDoc)example);
214         }
215         return null;
216     }
217
218     public Constraints constraints() {
219         synchronized (streamLock()) {
220             Constraint[] constraints = new Constraint[i_constraints.size()];
221             i_constraints.toArray(constraints);
222             return new QConstraints(i_trans, constraints);
223         }
224     }
225
226     public Query descend(final String JavaDoc a_field) {
227         synchronized (streamLock()) {
228             final QQuery query = new QQuery(i_trans, _this, a_field);
229             int[] run = { 1 };
230             if (!descend1(query, a_field, run)) {
231
232                 // try to add unparented nodes on the second run,
233
// if not added in the first run and a descendant
234
// was not found
235

236                 if (run[0] == 1) {
237                     run[0] = 2;
238                     if (!descend1(query, a_field, run)) {
239                         return null;
240                     }
241                 }
242             }
243             return query;
244         }
245     }
246
247     private boolean descend1(final QQuery query, final String JavaDoc a_field, int[] run) {
248         final boolean[] foundClass = { false };
249         if (run[0] == 2 || i_constraints.size() == 0) {
250
251             // On the second run we are really creating a second independant
252
// query network that is not joined to other higher level
253
// constraints.
254
// Let's see how this works out. We may need to join networks.
255

256             run[0] = 0; // prevent a double run of this code
257

258             final boolean[] anyClassCollected = { false };
259
260             stream().classCollection().attachQueryNode(a_field, new Visitor4() {
261
262                 public void visit(Object JavaDoc obj) {
263
264                     Object JavaDoc[] pair = ((Object JavaDoc[]) obj);
265                     YapClass parentYc = (YapClass)pair[0];
266                     YapField yf = (YapField)pair[1];
267                     YapClass childYc = yf.getFieldYapClass(stream());
268
269                     boolean take = true;
270
271                     if (childYc instanceof YapClassAny) {
272                         if (anyClassCollected[0]) {
273                             take = false;
274                         } else {
275                             anyClassCollected[0] = true;
276                         }
277                     }
278
279                     if (take) {
280
281                         QConClass qcc =
282                             new QConClass(
283                                 i_trans,
284                                 null,
285                                 yf.qField(i_trans),
286                                 parentYc.classReflector());
287                         addConstraint(qcc);
288                     }
289
290                 }
291
292             });
293
294         }
295         Iterator4 i = iterateConstraints();
296         while (i.moveNext()) {
297             if (((QCon)i.current()).attach(query, a_field)) {
298                 foundClass[0] = true;
299             }
300         }
301         return foundClass[0];
302     }
303
304     public ObjectSet execute() {
305         Callbacks callbacks = stream().callbacks();
306         callbacks.onQueryStarted(cast(this));
307         QueryResult qresult = getQueryResult();
308         callbacks.onQueryFinished(cast(this));
309         return new ObjectSetFacade(qresult);
310     }
311
312     public QueryResult getQueryResult() {
313         synchronized (streamLock()) {
314             if(i_constraints.size() == 0){
315                 return stream().getAll(i_trans);
316             }
317             QueryResult result = classOnlyQuery();
318             if(result != null) {
319                 return result;
320             }
321             return stream().executeQuery(_this);
322         }
323     }
324
325     protected YapStream stream() {
326         return i_trans.stream();
327     }
328
329     private QueryResult classOnlyQuery() {
330         
331         if(i_constraints.size()!=1||_comparator!=null) {
332             return null;
333         }
334         Constraint constr=singleConstraint();
335         if(constr.getClass()!=QConClass.class) {
336             return null;
337         }
338         QConClass clazzconstr=(QConClass)constr;
339         YapClass clazz=clazzconstr.i_yapClass;
340         if(clazz==null) {
341             return null;
342         }
343         if(clazzconstr.hasChildren() || clazz.isArray()) {
344             return null;
345         }
346         
347         QueryResult queryResult = stream().classOnlyQuery(i_trans, clazz);
348         if(queryResult == null){
349             return null;
350         }
351         sort(queryResult);
352         
353         return queryResult;
354         
355     }
356
357     private Constraint singleConstraint() {
358         return (Constraint)i_constraints.singleElement();
359     }
360
361     public static class CreateCandidateCollectionResult {
362         public final boolean checkDuplicates;
363         public final boolean topLevel;
364         public final List4 candidateCollection;
365         
366         public CreateCandidateCollectionResult(List4 candidateCollection_, boolean checkDuplicates_, boolean topLevel_) {
367             candidateCollection = candidateCollection_;
368             topLevel = topLevel_;
369             checkDuplicates = checkDuplicates_;
370         }
371     }
372     
373     public Iterator4 executeSnapshot(){
374         
375         final CreateCandidateCollectionResult r = createCandidateCollection();
376         
377         final Collection4 executionPath = executionPath(r);
378         
379         Iterator4 candidatesIterator = new Iterator4Impl(r.candidateCollection);
380         
381         Collection4 snapshots = new Collection4();
382         while(candidatesIterator.moveNext()){
383             QCandidates candidates = (QCandidates) candidatesIterator.current();
384             snapshots.add( candidates.executeSnapshot(executionPath));
385         }
386         
387         Iterator4 snapshotsIterator = snapshots.iterator();
388         final CompositeIterator4 resultingIDs = new CompositeIterator4(snapshotsIterator);
389         
390         if(!r.checkDuplicates){
391             return resultingIDs;
392         }
393         
394         return checkDuplicates(resultingIDs);
395     }
396     
397     public Iterator4 executeLazy(){
398         
399         final CreateCandidateCollectionResult r = createCandidateCollection();
400         
401         final Collection4 executionPath = executionPath(r);
402         
403         Iterator4 candidateCollection = new Iterator4Impl(r.candidateCollection);
404         
405         MappingIterator executeCandidates = new MappingIterator(candidateCollection){
406             protected Object JavaDoc map(Object JavaDoc current) {
407                 return ((QCandidates)current).executeLazy(executionPath);
408             }
409         };
410         
411         CompositeIterator4 resultingIDs = new CompositeIterator4(executeCandidates);
412         
413         if(!r.checkDuplicates){
414             return resultingIDs;
415         }
416         
417         return checkDuplicates(resultingIDs);
418     }
419
420     private MappingIterator checkDuplicates(CompositeIterator4 executeAllCandidates) {
421         return new MappingIterator(executeAllCandidates) {
422             private TreeInt ids = new TreeInt(0);
423             protected Object JavaDoc map(Object JavaDoc current) {
424                 int id = ((Integer JavaDoc)current).intValue();
425                 if(ids.find(id) != null){
426                     return MappingIterator.SKIP;
427                 }
428                 ids = (TreeInt)ids.add(new TreeInt(id));
429                 return current;
430             }
431
432         };
433     }
434
435     private Collection4 executionPath(final CreateCandidateCollectionResult r) {
436         return r.topLevel ? null : fieldPathFromTop();
437     }
438
439     public void executeLocal(final IdListQueryResult result) {
440         
441         CreateCandidateCollectionResult r = createCandidateCollection();
442         
443         boolean checkDuplicates = r.checkDuplicates;
444         boolean topLevel = r.topLevel;
445         List4 candidateCollection = r.candidateCollection;
446         
447         if (Debug.queries) {
448             logConstraints();
449         }
450         
451         if (candidateCollection != null) {
452             
453             final Collection4 executionPath = topLevel ? null : fieldPathFromTop();
454
455             Iterator4 i = new Iterator4Impl(candidateCollection);
456             while (i.moveNext()) {
457                 ((QCandidates)i.current()).execute();
458             }
459
460             if (candidateCollection._next != null) {
461                 checkDuplicates = true;
462             }
463
464             if (checkDuplicates) {
465                 result.checkDuplicates();
466             }
467
468             final YapStream stream = stream();
469             i = new Iterator4Impl(candidateCollection);
470             while (i.moveNext()) {
471                 QCandidates candidates = (QCandidates)i.current();
472                 if (topLevel) {
473                     candidates.traverse(result);
474                 } else {
475                     candidates.traverse(new Visitor4() {
476                         public void visit(Object JavaDoc a_object) {
477                             QCandidate candidate = (QCandidate)a_object;
478                             if (candidate.include()) {
479                                 TreeInt ids = new TreeInt(candidate._key);
480                                 final TreeInt[] idsNew = new TreeInt[1];
481                                 Iterator4 itPath = executionPath.iterator();
482                                 while (itPath.moveNext()) {
483                                     idsNew[0] = null;
484                                     final String JavaDoc fieldName = (String JavaDoc) (itPath.current());
485                                     if (ids != null) {
486                                         ids.traverse(new Visitor4() {
487                                             public void visit(Object JavaDoc treeInt) {
488                                                 int id = ((TreeInt)treeInt)._key;
489                                                 YapWriter reader =
490                                                     stream.readWriterByID(i_trans, id);
491                                                 if (reader != null) {
492                                                     ObjectHeader oh = new ObjectHeader(stream, reader);
493                                                     idsNew[0] = oh.yapClass().collectFieldIDs(
494                                                             oh._marshallerFamily,
495                                                             oh._headerAttributes,
496                                                             idsNew[0],
497                                                             reader,
498                                                             fieldName);
499                                                 }
500                                             }
501                                         });
502                                     }
503                                     ids = idsNew[0];
504                                 }
505                                 if(ids != null){
506                                     ids.traverse(new Visitor4() {
507                                         public void visit(Object JavaDoc treeInt) {
508                                             result.addKeyCheckDuplicates(((TreeInt)treeInt)._key);
509                                         }
510                                     });
511                                 }
512                             }
513                         }
514                     });
515                 }
516             }
517         }
518         sort(result);
519 // result.reset();
520
}
521     
522     private Collection4 fieldPathFromTop(){
523         QQueryBase q = this;
524         final Collection4 fieldPath = new Collection4();
525         while (q.i_parent != null) {
526             fieldPath.prepend(q.i_field);
527             q = q.i_parent;
528         }
529         return fieldPath;
530     }
531
532     private void logConstraints() {
533         if (Debug.queries) {
534             Iterator4 i = iterateConstraints();
535             while (i.moveNext()) {
536                 ((QCon)i.current()).log("");
537             }
538         }
539     }
540
541     public CreateCandidateCollectionResult createCandidateCollection() {
542         boolean checkDuplicates = false;
543         boolean topLevel = true;
544         List4 candidateCollection = null;
545         Iterator4 i = iterateConstraints();
546         while (i.moveNext()) {
547             QCon qcon = (QCon)i.current();
548             QCon old = qcon;
549             qcon = qcon.getRoot();
550             if (qcon != old) {
551                 checkDuplicates = true;
552                 topLevel = false;
553             }
554             YapClass yc = qcon.getYapClass();
555             if (yc == null) {
556                 break;
557             }
558             candidateCollection = addConstraintToCandidateCollection(candidateCollection, qcon);
559         }
560         return new CreateCandidateCollectionResult(candidateCollection, checkDuplicates, topLevel);
561     }
562
563     private List4 addConstraintToCandidateCollection(List4 candidateCollection, QCon qcon) {
564         
565         if (candidateCollection != null) {
566             if (tryToAddToExistingCandidate(candidateCollection, qcon)) {
567                 return candidateCollection;
568             }
569         }
570         
571         QCandidates candidates = new QCandidates(i_trans, qcon.getYapClass(), null);
572         candidates.addConstraint(qcon);
573         return new List4(candidateCollection, candidates);
574     }
575
576     private boolean tryToAddToExistingCandidate(List4 candidateCollection, QCon qcon) {
577         Iterator4 j = new Iterator4Impl(candidateCollection);
578         while (j.moveNext()) {
579             QCandidates candidates = (QCandidates)j.current();
580             if (candidates.tryAddConstraint(qcon)) {
581                 return true;
582             }
583         }
584         return false;
585     }
586
587     public final Transaction getTransaction() {
588         return i_trans;
589     }
590     
591     Iterator4 iterateConstraints(){
592         // clone the collection first to avoid
593
// InvalidIteratorException as i_constraints might be
594
// modified during the execution of callee
595
return new Collection4(i_constraints).iterator();
596     }
597
598     public Query orderAscending() {
599         synchronized (streamLock()) {
600             setOrdering(i_orderingGenerator.next());
601             return _this;
602         }
603     }
604
605     public Query orderDescending() {
606         synchronized (streamLock()) {
607             setOrdering(-i_orderingGenerator.next());
608             return _this;
609         }
610     }
611
612     private void setOrdering(final int ordering) {
613         Iterator4 i = iterateConstraints();
614         while (i.moveNext()) {
615             ((QCon)i.current()).setOrdering(ordering);
616         }
617     }
618     
619     public void marshall() {
620         _evaluationModeAsInt = _evaluationMode.asInt();
621         Iterator4 i = iterateConstraints();
622         while (i.moveNext()) {
623             ((QCon)i.current()).getRoot().marshall();
624         }
625     }
626
627     public void unmarshall(final Transaction a_trans) {
628         _evaluationMode = QueryEvaluationMode.fromInt(_evaluationModeAsInt);
629         i_trans = a_trans;
630         Iterator4 i = iterateConstraints();
631         while (i.moveNext()) {
632             ((QCon)i.current()).unmarshall(a_trans);
633         }
634     }
635
636     void removeConstraint(QCon a_constraint) {
637         i_constraints.remove(a_constraint);
638     }
639
640     Constraint toConstraint(final Collection4 constraints) {
641         if (constraints.size() == 1) {
642             return (Constraint) constraints.singleElement();
643         } else if (constraints.size() > 0) {
644             Constraint[] constraintArray = new Constraint[constraints.size()];
645             constraints.toArray(constraintArray);
646             return new QConstraints(i_trans, constraintArray);
647         }
648         return null;
649     }
650     
651     protected Object JavaDoc streamLock() {
652         return stream().i_lock;
653     }
654
655     public Query sortBy(QueryComparator comparator) {
656         _comparator=comparator;
657         return _this;
658     }
659     
660     private void sort(QueryResult result) {
661         if(_comparator!=null) {
662             result.sort(_comparator);
663         }
664     }
665     
666     // cheat emulating '(QQuery)this'
667
private static QQuery cast(QQueryBase obj) {
668         return (QQuery)obj;
669     }
670     
671     public boolean requiresSort() {
672         if (_comparator != null){
673             return true;
674         }
675         Iterator4 i = iterateConstraints();
676         while(i.moveNext()){
677             QCon qCon = (QCon) i.current();
678             if(qCon.requiresSort()){
679                 return true;
680             }
681         }
682         return false;
683     }
684     
685     public QueryComparator comparator() {
686         return _comparator;
687     }
688     
689     public QueryEvaluationMode evaluationMode(){
690         return _evaluationMode;
691     }
692     
693     public void evaluationMode(QueryEvaluationMode mode){
694         _evaluationMode = mode;
695     }
696
697 }
698
Popular Tags