KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > db4o > QCandidate


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.marshall.*;
26 import com.db4o.query.*;
27 import com.db4o.reflect.*;
28
29 /**
30  * Represents an actual object in the database. Forms a tree structure, indexed
31  * by id. Can have dependents that are doNotInclude'd in the query result when
32  * this is doNotInclude'd.
33  *
34  * @exclude
35  */

36 public class QCandidate extends TreeInt implements Candidate, Orderable {
37
38     // db4o ID is stored in i_key;
39

40     // db4o byte stream storing the object
41
YapReader _bytes;
42
43     final QCandidates _candidates;
44
45     // Dependant candidates
46
private List4 _dependants;
47
48     // whether to include in the result set
49
// may use id for optimisation ???
50
boolean _include = true;
51
52     private Object JavaDoc _member;
53
54     // Comparable
55
Orderable _order;
56
57     // Possible pending joins on children
58
Tree _pendingJoins;
59
60     // The evaluation root to compare all ORs
61
private QCandidate _root;
62
63     // the YapClass of this object
64
YapClass _yapClass;
65
66     // temporary yapField and member for one field during evaluation
67
YapField _yapField; // null denotes null object
68

69     MarshallerFamily _marshallerFamily;
70
71     private QCandidate(QCandidates qcandidates) {
72         super(0);
73         _candidates = qcandidates;
74     }
75
76     private QCandidate() {
77         this(null);
78         // dummy constructor to get "this" out of declaration for C#
79
}
80
81     public QCandidate(QCandidates candidates, Object JavaDoc obj, int id, boolean include) {
82         super(id);
83         if (DTrace.enabled) {
84             DTrace.CREATE_CANDIDATE.log(id);
85         }
86         _candidates = candidates;
87         _order = this;
88         _member = obj;
89         _include = include;
90         
91         if(id == 0){
92             _key = candidates.generateCandidateId();
93         }
94     }
95
96     public Object JavaDoc shallowClone() {
97         QCandidate qcan = new QCandidate(_candidates);
98         qcan.setBytes(_bytes);
99         qcan._dependants = _dependants;
100         qcan._include = _include;
101         qcan._member = _member;
102         qcan._order = _order;
103         qcan._pendingJoins = _pendingJoins;
104         qcan._root = _root;
105         qcan._yapClass = _yapClass;
106         qcan._yapField = _yapField;
107
108         return super.shallowCloneInternal(qcan);
109     }
110
111     void addDependant(QCandidate a_candidate) {
112         _dependants = new List4(_dependants, a_candidate);
113     }
114
115     private void checkInstanceOfCompare() {
116         if (_member instanceof Compare) {
117             _member = ((Compare) _member).compare();
118             YapFile stream = getStream();
119             _yapClass = stream.getYapClass(stream.reflector().forObject(_member));
120             _key = (int) stream.getID(_member);
121             setBytes(stream.readReaderByID(getTransaction(), _key));
122         }
123     }
124
125     public int compare(Tree a_to) {
126         return _order.compareTo(((QCandidate) a_to)._order);
127     }
128
129     public int compareTo(Object JavaDoc a_object) {
130         return _key - ((TreeInt) a_object)._key;
131     }
132
133     boolean createChild(final QCandidates a_candidates) {
134         if (!_include) {
135             return false;
136         }
137
138         if (_yapField != null) {
139             TypeHandler4 handler = _yapField.getHandler();
140             if (handler != null) {
141
142                 final YapReader[] arrayBytes = { _bytes };
143                 
144                 final TypeHandler4 arrayHandler = handler.readArrayHandler(
145                         getTransaction(), _marshallerFamily, arrayBytes);
146
147                 if (arrayHandler != null) {
148
149                     final int offset = arrayBytes[0]._offset;
150                     boolean outerRes = true;
151
152                     // The following construct is worse than not ideal.
153
// For each constraint it completely reads the
154
// underlying structure again. The structure could b
155
// kept fairly easy. TODO: Optimize!
156

157                     Iterator4 i = a_candidates.iterateConstraints();
158                     while (i.moveNext()) {
159
160                         QCon qcon = (QCon) i.current();
161                         QField qf = qcon.getField();
162                         if (qf == null || qf.i_name.equals(_yapField.getName())) {
163
164                             QCon tempParent = qcon.i_parent;
165                             qcon.setParent(null);
166
167                             final QCandidates candidates = new QCandidates(
168                                     a_candidates.i_trans, null, qf);
169                             candidates.addConstraint(qcon);
170
171                             qcon.setCandidates(candidates);
172                             arrayHandler.readCandidates(_marshallerFamily,arrayBytes[0], candidates);
173                             arrayBytes[0]._offset = offset;
174
175                             final boolean isNot = qcon.isNot();
176                             if (isNot) {
177                                 qcon.removeNot();
178                             }
179
180                             candidates.evaluate();
181
182                             final Tree.ByRef pending = new Tree.ByRef();
183                             final boolean[] innerRes = { isNot };
184                             candidates.traverse(new Visitor4() {
185                                 public void visit(Object JavaDoc obj) {
186
187                                     QCandidate cand = (QCandidate) obj;
188
189                                     if (cand.include()) {
190                                         innerRes[0] = !isNot;
191                                     }
192
193                                     // Collect all pending subresults.
194

195                                     if (cand._pendingJoins != null) {
196                                         cand._pendingJoins
197                                                 .traverse(new Visitor4() {
198                                                     public void visit(
199                                                             Object JavaDoc a_object) {
200                                                         QPending newPending = (QPending) a_object;
201
202                                                         // We need to change
203
// the
204
// constraint here, so
205
// our
206
// pending collector
207
// uses
208
// the right
209
// comparator.
210
newPending
211                                                                 .changeConstraint();
212                                                         QPending oldPending = (QPending) Tree
213                                                                 .find(
214                                                                         pending.value,
215                                                                         newPending);
216                                                         if (oldPending != null) {
217
218                                                             // We only keep one
219
// pending result
220
// for
221
// all array
222
// elements.
223
// and memorize,
224
// whether we had a
225
// true or a false
226
// result.
227
// or both.
228

229                                                             if (oldPending._result != newPending._result) {
230                                                                 oldPending._result = QPending.BOTH;
231                                                             }
232
233                                                         } else {
234                                                             pending.value = Tree
235                                                                     .add(
236                                                                             pending.value,
237                                                                             newPending);
238                                                         }
239                                                     }
240                                                 });
241                                     }
242                                 }
243                             });
244
245                             if (isNot) {
246                                 qcon.not();
247                             }
248
249                             // In case we had pending subresults, we
250
// need to communicate
251
// them up to our root.
252
if (pending.value != null) {
253                                 pending.value.traverse(new Visitor4() {
254                                     public void visit(Object JavaDoc a_object) {
255                                         getRoot().evaluate((QPending) a_object);
256                                     }
257                                 });
258                             }
259
260                             if (!innerRes[0]) {
261
262                                 if (Debug.queries) {
263                                     System.out
264                                             .println(" Array evaluation false. Constraint:"
265                                                     + qcon.i_id);
266                                 }
267
268                                 // Again this could be double triggering.
269
//
270
// We want to clean up the "No route"
271
// at some stage.
272

273                                 qcon.visit(getRoot(), qcon.evaluator().not(false));
274
275                                 outerRes = false;
276                             }
277
278                             qcon.setParent(tempParent);
279
280                         }
281                     }
282
283                     return outerRes;
284                 }
285
286                 // We may get simple types here too, if the YapField was null
287
// in the higher level simple evaluation. Evaluate these
288
// immediately.
289

290                 if (handler.getTypeID() == YapConst.TYPE_SIMPLE) {
291                     a_candidates.i_currentConstraint.visit(this);
292                     return true;
293                 }
294             }
295         }
296         
297         if(_yapField == null || _yapField instanceof YapFieldNull){
298             return false;
299         }
300         
301         _yapClass.findOffset(_bytes, _yapField);
302         QCandidate candidate = readSubCandidate(a_candidates);
303         if (candidate == null) {
304             return false;
305         }
306
307         // fast early check for YapClass
308
if (a_candidates.i_yapClass != null
309                 && a_candidates.i_yapClass.isStrongTyped()) {
310             if (_yapField != null) {
311                 TypeHandler4 handler = _yapField.getHandler();
312                 if (handler != null
313                         && (handler.getTypeID() == YapConst.TYPE_CLASS)) {
314                     YapClass yc = (YapClass) handler;
315                     if (yc instanceof YapClassAny) {
316                         yc = candidate.readYapClass();
317                     }
318                     if(yc == null){
319                         return false;
320                     }
321                     if (!yc.canHold(a_candidates.i_yapClass.classReflector())) {
322                         return false;
323                     }
324                 }
325             }
326         }
327
328         addDependant(a_candidates.addByIdentity(candidate));
329         return true;
330     }
331
332     void doNotInclude() {
333         _include = false;
334         if (_dependants != null) {
335             Iterator4 i = new Iterator4Impl(_dependants);
336             _dependants = null;
337             while (i.moveNext()) {
338                 ((QCandidate) i.current()).doNotInclude();
339             }
340         }
341     }
342
343     public boolean duplicates() {
344         return _order.hasDuplicates();
345     }
346
347     boolean evaluate(final QConObject a_constraint, final QE a_evaluator) {
348         if (a_evaluator.identity()) {
349             return a_evaluator.evaluate(a_constraint, this, null);
350         }
351         if (_member == null) {
352             _member = value();
353         }
354         return a_evaluator.evaluate(a_constraint, this, a_constraint
355                 .translate(_member));
356     }
357
358     boolean evaluate(QPending a_pending) {
359
360         if (Debug.queries) {
361             System.out.println("Pending arrived Join: " + a_pending._join.i_id
362                     + " Constraint:" + a_pending._constraint.i_id + " res:"
363                     + a_pending._result);
364         }
365
366         QPending oldPending = (QPending) Tree.find(_pendingJoins, a_pending);
367
368         if (oldPending == null) {
369             a_pending.changeConstraint();
370             _pendingJoins = Tree.add(_pendingJoins, a_pending);
371             return true;
372         }
373         _pendingJoins = _pendingJoins.removeNode(oldPending);
374         oldPending._join.evaluatePending(this, oldPending, a_pending._result);
375         return false;
376     }
377
378     ReflectClass classReflector() {
379         readYapClass();
380         if (_yapClass == null) {
381             return null;
382         }
383         return _yapClass.classReflector();
384     }
385
386     // / ***<Candidate interface code>***
387

388     public ObjectContainer objectContainer() {
389         return getStream();
390     }
391
392     public Object JavaDoc getObject() {
393         Object JavaDoc obj = value(true);
394         if (obj instanceof YapReader) {
395             YapReader reader = (YapReader) obj;
396             int offset = reader._offset;
397             obj = _marshallerFamily._string.readFromOwnSlot(getStream(), reader);
398             reader._offset = offset;
399         }
400         return obj;
401     }
402
403     QCandidate getRoot() {
404         return _root == null ? this : _root;
405     }
406
407     private YapFile getStream() {
408         return getTransaction().i_file;
409     }
410
411     private Transaction getTransaction() {
412         return _candidates.i_trans;
413     }
414
415     public boolean hasDuplicates() {
416
417         // Subcandidates are evaluated along with their constraints
418
// in one big QCandidates object. The tree can have duplicates
419
// so evaluation can be cascaded up to different roots.
420

421         return _root != null;
422     }
423
424     public void hintOrder(int a_order, boolean a_major) {
425         _order = new Order();
426         _order.hintOrder(a_order, a_major);
427     }
428
429     public boolean include() {
430         return _include;
431     }
432
433     /**
434      * For external interface use only. Call doNotInclude() internally so
435      * dependancies can be checked.
436      */

437     public void include(boolean flag) {
438         // TODO:
439
// Internal and external flag may need to be handled seperately.
440
_include = flag;
441     }
442
443     public void isDuplicateOf(Tree a_tree) {
444         _size = 0;
445         _root = (QCandidate) a_tree;
446     }
447
448     private ReflectClass memberClass() {
449         return getTransaction().reflector().forObject(_member);
450     }
451
452     YapComparable prepareComparison(YapStream a_stream, Object JavaDoc a_constraint) {
453         if (_yapField != null) {
454             return _yapField.prepareComparison(a_constraint);
455         }
456         if (_yapClass == null) {
457
458             YapClass yc = null;
459             if (_bytes != null) {
460                 yc = a_stream.produceYapClass(a_stream.reflector().forObject(a_constraint));
461             } else {
462                 if (_member != null) {
463                     yc = a_stream.getYapClass(a_stream.reflector().forObject(_member));
464                 }
465             }
466             if (yc != null) {
467                 if (_member != null && _member.getClass().isArray()) {
468                     TypeHandler4 ydt = (TypeHandler4) yc
469                             .prepareComparison(a_constraint);
470                     if (a_stream.reflector().array().isNDimensional(
471                             memberClass())) {
472                         YapArrayN yan = new YapArrayN(a_stream, ydt, false);
473                         return yan;
474                     }
475                     YapArray ya = new YapArray(a_stream, ydt, false);
476                     return ya;
477                     
478                 }
479                 return yc.prepareComparison(a_constraint);
480                 
481             }
482             return null;
483         }
484         return _yapClass.prepareComparison(a_constraint);
485     }
486
487     private void read() {
488         if (_include) {
489             if (_bytes == null) {
490                 if (_key > 0) {
491                     if (DTrace.enabled) {
492                         DTrace.CANDIDATE_READ.log(_key);
493                     }
494                     setBytes(getStream().readReaderByID(getTransaction(), _key));
495                     if (_bytes == null) {
496                         _include = false;
497                     }
498                 } else {
499                     _include = false;
500                 }
501             }
502         }
503     }
504
505     private QCandidate readSubCandidate(QCandidates candidateCollection) {
506         read();
507         if (_bytes != null) {
508             
509             QCandidate subCandidate = null;
510             final int offset = _bytes._offset;
511             try {
512                 subCandidate = _yapField.i_handler.readSubCandidate(_marshallerFamily, _bytes, candidateCollection, false);
513             } catch (Exception JavaDoc e) {
514                 return null;
515             }
516             _bytes._offset = offset;
517
518             if (subCandidate != null) {
519                 subCandidate._root = getRoot();
520                 return subCandidate;
521             }
522         }
523         return null;
524     }
525
526     private void readThis(boolean a_activate) {
527         read();
528
529         Transaction trans = getTransaction();
530         if (trans != null) {
531
532             _member = trans.stream().getByID1(trans, _key);
533
534             if (_member != null && (a_activate || _member instanceof Compare)) {
535                 trans.stream().activate1(trans, _member);
536                 checkInstanceOfCompare();
537             }
538         }
539     }
540
541     YapClass readYapClass() {
542         if (_yapClass == null) {
543             read();
544             if (_bytes != null) {
545
546                 _bytes._offset = 0;
547                 
548                 YapStream stream = getStream();
549                 ObjectHeader objectHeader = new ObjectHeader(stream, _bytes);
550                 _yapClass = objectHeader.yapClass();
551                 
552                 if (_yapClass != null) {
553                     if (stream.i_handlers.ICLASS_COMPARE
554                             .isAssignableFrom(_yapClass.classReflector())) {
555                         readThis(false);
556                     }
557                 }
558             }
559         }
560         return _yapClass;
561     }
562
563     public String JavaDoc toString() {
564         if (!Debug4.prettyToStrings) {
565             return super.toString();
566         }
567         String JavaDoc str = "QCandidate ";
568         if (_yapClass != null) {
569             str += "\n YapClass " + _yapClass.getName();
570         }
571         if (_yapField != null) {
572             str += "\n YapField " + _yapField.getName();
573         }
574         if (_member != null) {
575             str += "\n Member " + _member.toString();
576         }
577         if (_root != null) {
578             str += "\n rooted by:\n";
579             str += _root.toString();
580         } else {
581             str += "\n ROOT";
582         }
583         return str;
584     }
585
586     void useField(QField a_field) {
587         read();
588         if (_bytes == null) {
589             _yapField = null;
590             return;
591         }
592         readYapClass();
593         _member = null;
594         if (a_field == null) {
595             _yapField = null;
596             return;
597         }
598         if (_yapClass == null) {
599             _yapField = null;
600             return;
601         }
602         _yapField = a_field.getYapField(_yapClass);
603         
604         _marshallerFamily = _yapClass.findOffset(_bytes, _yapField);
605         
606         if (_yapField == null || _marshallerFamily == null ) {
607             if (_yapClass.holdsAnyClass()) {
608                 // TODO: What does this mean?
609
_yapField = null;
610             } else {
611                 // TODO: And now what does this mean and whats the difference?
612

613                 _yapField = new YapFieldNull();
614             }
615         }
616     }
617
618     Object JavaDoc value() {
619         return value(false);
620     }
621
622     // TODO: This is only used for Evaluations. Handling may need
623
// to be different for collections also.
624
Object JavaDoc value(boolean a_activate) {
625         if (_member == null) {
626             if (_yapField == null) {
627                 readThis(a_activate);
628             } else {
629                 // FIXME: Should _bytes ever be null here?
630
int offset = _bytes._offset;
631                 try {
632                     _member = _yapField.readQuery(getTransaction(),_marshallerFamily, _bytes);
633                 } catch (CorruptionException ce) {
634                     _member = null;
635                 }
636                 _bytes._offset = offset;
637                 checkInstanceOfCompare();
638             }
639         }
640         return _member;
641     }
642     
643     void setBytes(YapReader bytes){
644         _bytes = bytes;
645     }
646 }
647
Popular Tags