KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > josql > expressions > SubQueryExpression


1 /*
2  * Copyright 2004-2005 Gary Bentley
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may
5  * not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */

15 package org.josql.expressions;
16
17 import java.util.Map JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Iterator JavaDoc;
22
23 import com.gentlyweb.utils.Getter;
24
25 import org.josql.Query;
26 import org.josql.QueryResults;
27 import org.josql.QueryExecutionException;
28 import org.josql.QueryParseException;
29
30 import org.josql.internal.Utilities;
31
32 import org.josql.events.*;
33
34 public class SubQueryExpression extends ValueExpression implements BindVariableChangedListener,
35                                        SaveValueChangedListener
36 {
37
38     private Query q = null;
39     private boolean inited = false;
40     private String JavaDoc acc = null;
41     private Getter get = null;
42     private boolean nullQuery = false;
43
44     public SubQueryExpression (Query q)
45     {
46
47     this.q = q;
48
49     this.q.addBindVariableChangedListener (this);
50     this.q.addSaveValueChangedListener (this);
51
52     }
53
54     public void bindVariableChanged (BindVariableChangedEvent ev)
55     {
56
57     if (this.q.getFrom () instanceof BindVariable)
58     {
59
60         BindVariable bv = (BindVariable) this.q.getFrom ();
61
62         if (bv.getName ().equalsIgnoreCase (ev.getName ()))
63         {
64
65         this.inited = false;
66
67         }
68
69     }
70
71     }
72
73     public void saveValueChanged (SaveValueChangedEvent ev)
74     {
75
76     if (this.q.getFrom () instanceof SaveValue)
77     {
78
79         SaveValue sv = (SaveValue) this.q.getFrom ();
80
81         if (sv.getName ().equalsIgnoreCase (ev.getName ()))
82         {
83
84         this.inited = false;
85
86         }
87
88     }
89
90     }
91
92     public Getter getGetter ()
93     {
94
95     return this.get;
96
97     }
98
99     public void setAccessor (String JavaDoc acc)
100     {
101
102     this.acc = acc;
103
104     }
105
106     public String JavaDoc getAccessor ()
107     {
108
109     return this.acc;
110
111     }
112
113     public Query getQuery ()
114     {
115
116     return this.q;
117
118     }
119
120     public boolean hasFixedResult (Query q)
121     {
122
123     return false;
124
125     }
126
127     public Class JavaDoc getExpectedReturnType (Query q)
128                                     throws QueryParseException
129     {
130
131     if (this.get != null)
132     {
133
134         return this.get.getType ();
135
136     }
137
138     return List JavaDoc.class;
139
140     }
141
142     public void init (Query q)
143                   throws QueryParseException
144     {
145
146     // Now see if we have an accessor for the function.
147
if (this.acc != null)
148     {
149
150         try
151         {
152
153         this.get = new Getter (this.acc,
154                        ArrayList JavaDoc.class);
155             
156         } catch (Exception JavaDoc e) {
157
158         throw new QueryParseException ("Sub-query: " +
159                            this +
160                            " has accessor: " +
161                            this.acc +
162                            " however no valid accessor has been found in return type: " +
163                            ArrayList JavaDoc.class.getName (),
164                            e);
165
166         }
167
168     }
169
170     }
171
172     public boolean isTrue (Object JavaDoc o,
173                Query q)
174                        throws QueryExecutionException
175     {
176
177     List JavaDoc l = (List JavaDoc) this.getValue (o,
178                        q);
179
180     return l.size () > 0;
181
182     }
183
184     private void innerInit (Object JavaDoc o,
185                 Query q)
186                         throws QueryExecutionException
187     {
188
189     Object JavaDoc obj = null;
190
191     Expression from = this.q.getFrom ();
192
193     if (from instanceof ConstantExpression)
194     {
195
196         // Assume this is a getter.
197
String JavaDoc g = (String JavaDoc) from.getValue (null,
198                            this.q);
199
200         // See if it's the "special" null.
201
if (!g.equalsIgnoreCase ("null"))
202         {
203
204         Accessor acc = new Accessor ();
205
206         acc.setAccessor (g);
207
208         this.q.setFrom (acc);
209         
210         try
211         {
212
213             // Init the accessor (from) but with our parent.
214
acc.init (q);
215
216         } catch (Exception JavaDoc e) {
217             
218             throw new QueryExecutionException ("Unable to init accessor: " +
219                                g +
220                                " from class: " +
221                                o.getClass () +
222                                " for FROM clause, for sub-query: \"" +
223                                this.q +
224                                "\"",
225                                e);
226             
227         }
228
229         // Get the value, this will constitute the class for our query.
230
obj = this.q.getFrom ().getValue (o,
231                           this.q);
232
233         } else {
234
235         // This is a "null" query.
236
List JavaDoc l = new ArrayList JavaDoc ();
237         l.add (new Object JavaDoc ());
238
239         obj = l;
240
241         this.nullQuery = true;
242
243         }
244
245     }
246
247     if (from instanceof Accessor)
248     {
249
250         // Get the value, this will constitute the class for our query.
251
obj = this.q.getFrom ().getValue (o,
252                           this.q);
253
254     }
255
256     if (from instanceof Function)
257     {
258
259         try
260         {
261
262         from.init (this.q);
263
264         } catch (Exception JavaDoc e) {
265
266         throw new QueryExecutionException ("Unable to init FROM clause: " +
267                            from +
268                            " for sub-query: " +
269                            this.q,
270                            e);
271
272         }
273
274         // Need to pass the parent query here to ensure that if we are using any
275
// special bind variables they are gained from the correct place.
276
obj = this.q.getFrom ().getValue (o,
277                           q);
278
279     }
280
281     if (from instanceof SaveValue)
282     {
283
284         obj = from.getValue (o,
285                  q.getTopLevelQuery ());
286
287     }
288
289     if (from instanceof BindVariable)
290     {
291
292         // Need to init the bind variable.
293
try
294         {
295
296         from.init (q.getTopLevelQuery ());
297
298         } catch (Exception JavaDoc e) {
299
300         throw new QueryExecutionException ("Unable to init FROM clause: " +
301                            from +
302                            " for sub-query: " +
303                            this.q,
304                            e);
305
306         }
307
308         obj = from.getValue (o,
309                  q.getTopLevelQuery ());
310         
311     }
312
313     if (obj == null)
314     {
315
316         return;
317
318     }
319
320     // Need to ensure that obj is an instance of Collection.
321
if (!(obj instanceof Collection JavaDoc))
322     {
323
324         throw new QueryExecutionException ("Expected FROM clause: " +
325                            this.q.getFrom () +
326                            " for sub-query: " +
327                            this.q +
328                            " to evaluate to an instance of: " +
329                            Collection JavaDoc.class.getName () +
330                            ", instead evaluates to: " +
331                            obj.getClass ().getName () +
332                            " using from expression: " +
333                            from);
334
335     }
336
337     Collection JavaDoc col = (Collection JavaDoc) obj;
338     
339     // Now peek at the top of the collection.
340
Iterator JavaDoc iter = col.iterator ();
341     
342     if (!iter.hasNext ())
343     {
344
345         return;
346
347     }
348
349     Object JavaDoc io = iter.next ();
350     
351     // Get the class...
352
if (io == null)
353     {
354
355         // Crapola! Now need to iterate down the collection until we find
356
// an item that is not null.
357
while (iter.hasNext ())
358         {
359
360         io = iter.next ();
361
362         if (io != null)
363         {
364
365             break;
366
367         }
368
369         }
370
371     }
372
373     if (io == null)
374     {
375
376         // Just return, no elements.
377
return;
378
379     }
380
381     this.q.setFromObjectClass (io.getClass ());
382
383     try
384     {
385
386         this.q.init ();
387
388     } catch (Exception JavaDoc e) {
389
390         throw new QueryExecutionException ("Unable to init sub-query: " +
391                            this.q +
392                            " with class: " +
393                            io.getClass ().getName (),
394                            e);
395
396     }
397
398     this.inited = true;
399
400     }
401
402     private List JavaDoc innerGetValue (Object JavaDoc o,
403                 Query q)
404                             throws QueryExecutionException
405     {
406
407     if (this.nullQuery)
408     {
409
410         return Query.nullQueryList;
411
412     }
413
414     Object JavaDoc obj = null;
415
416     try
417     {
418
419         obj = this.q.getFrom ().getValue (o,
420                           this.q.getTopLevelQuery ());
421
422     } catch (Exception JavaDoc e) {
423         
424         throw new QueryExecutionException ("Unable to evaluate FROM clause accessor: " +
425                            this.q.getFrom () +
426                            " for sub-query: " +
427                            this.q,
428                            e);
429
430     }
431
432     if (obj == null)
433     {
434
435         return new ArrayList JavaDoc ();
436
437     }
438
439     if (!(obj instanceof Collection JavaDoc))
440     {
441
442         throw new QueryExecutionException ("Evaluation of FROM clause for sub-query: " +
443                            this.q +
444                            " returns an instance of: " +
445                            obj.getClass ().getName () +
446                            " however only sub-classes of: " +
447                            Collection JavaDoc.class.getName () +
448                            " are supported.");
449
450     }
451
452     List JavaDoc l = null;
453
454     // Now, co-erce the collection to a List.
455
if (obj instanceof List JavaDoc)
456     {
457
458         l = (List JavaDoc) obj;
459         
460     } else {
461
462         l = new ArrayList JavaDoc ((Collection JavaDoc) obj);
463
464     }
465
466     return l;
467
468     }
469
470     public Object JavaDoc evaluate (Object JavaDoc o,
471                 Query q)
472                         throws QueryExecutionException
473     {
474
475     this.q.setParent (q);
476
477     if (!this.inited)
478     {
479
480         this.innerInit (o,
481                 q);
482
483     }
484
485     if (this.inited)
486     {
487
488         List JavaDoc l = this.innerGetValue (o,
489                      q);
490
491         QueryResults qr = this.q.execute (l);
492
493         if (this.get != null)
494         {
495
496         try
497         {
498
499             return this.get.getValue (qr.getResults ());
500
501         } catch (Exception JavaDoc e) {
502
503             throw new QueryExecutionException ("Unable to get value for accessor: " +
504                                this.acc +
505                                " from return type: " +
506                                ArrayList JavaDoc.class.getName () +
507                                " after execution of sub-query: " +
508                                this,
509                                e);
510
511         }
512
513         }
514
515         return qr.getResults ();
516
517     }
518
519     return new ArrayList JavaDoc ();
520
521     }
522
523     public String JavaDoc toString ()
524     {
525
526     return "(" + this.q.toString () + ")";
527  
528     }
529
530 }
531
Popular Tags