KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > ejb > VersantEjbQueryImp


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.ejb;
13
14 import com.versant.core.common.NewObjectOID;
15 import com.versant.core.metadata.ClassMetaData;
16 import com.versant.core.metadata.FetchGroup;
17 import com.versant.core.server.CompiledQuery;
18 import com.versant.core.util.BeanUtils;
19
20 import javax.jdo.Extent;
21 import javax.jdo.PersistenceManager;
22 import javax.jdo.spi.PersistenceCapable;
23 import javax.persistence.Query;
24 import javax.persistence.TemporalType;
25 import javax.persistence.FlushModeType;
26 import java.io.Externalizable JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.ObjectInput JavaDoc;
29 import java.io.ObjectOutput JavaDoc;
30 import java.util.*;
31
32 import com.versant.core.common.BindingSupportImpl;
33 import com.versant.core.jdo.*;
34
35 /**
36  * This is the implementation of a Query.
37  */

38 public final class VersantEjbQueryImp implements Externalizable JavaDoc, Query {
39     private Object JavaDoc[] params = new Object JavaDoc[5];
40
41     private final QueryDetails queryDetails = new QueryDetails();
42     private QueryResult resultList;
43     private EMProxy pmProxy;
44     private CompiledQuery compiledQuery;
45     private int paramEndIndex = -1;
46
47     /**
48      * For Serialization.
49      */

50     public VersantEjbQueryImp() {
51     }
52
53     public VersantEjbQueryImp(EMProxy emProxy, String JavaDoc filter) {
54         this(emProxy, QueryDetails.LANGUAGE_EJBQL);
55         queryDetails.setFilter(filter);
56     }
57
58     /**
59      * Create a new query for pmProxy. The ignoreCache setting is taken
60      * from the curremt setting of pmProxy.
61      *
62      * @param language Query language
63      * @see com.versant.core.jdo.QueryDetails#LANGUAGE_JDOQL
64      * @see com.versant.core.jdo.QueryDetails#LANGUAGE_SQL
65      * @see com.versant.core.jdo.QueryDetails#LANGUAGE_EJBQL
66      */

67     public VersantEjbQueryImp(EMProxy pmProxy, int language) {
68         this.pmProxy = pmProxy;
69         queryDetails.setLanguage(language);
70     }
71
72     /**
73      * Create a new query for pmProxy using all the settings of params.
74      * This is used to create Query's from named queries in the meta data.
75      */

76     public VersantEjbQueryImp(EMProxy pmProxy, QueryDetails params) {
77         this.pmProxy = pmProxy;
78         queryDetails.fillFrom(params);
79     }
80
81     /**
82      * This is a util method that invalidates the preCompiled query because of
83      * change made by the client.
84      */

85     private void changed() {
86         compiledQuery = null;
87     }
88
89     public List getResultList() {
90         if (paramEndIndex >= 0) {
91             if (params.length > paramEndIndex + 1) {
92                 Object JavaDoc[] tmp = new Object JavaDoc[paramEndIndex + 1];
93                 System.arraycopy(params, 0, tmp, 0, tmp.length);
94                 params = tmp;
95             }
96             return (List) executeWithArray(params);
97         }
98         return (List) execute();
99     }
100
101     public Object JavaDoc getSingleResult() {
102         return null;
103     }
104
105     public int executeUpdate() {
106         return 0;
107     }
108
109     public Query setMaxResults(int maxResult) {
110         queryDetails.setMaxResultCount(maxResult);
111         return this;
112     }
113
114     public Query setFirstResult(int startPosition) {
115         return this;
116     }
117
118     public Query setHint(String JavaDoc hintName, Object JavaDoc value) {
119         return this;
120     }
121
122     public Query setParameter(String JavaDoc name, Object JavaDoc value) {
123         return this;
124     }
125
126     public Query setParameter(String JavaDoc name, Date value, TemporalType temporalType) {
127         return this;
128     }
129
130     public Query setParameter(String JavaDoc name, Calendar value, TemporalType temporalType) {
131         return this;
132     }
133
134     public Query setParameter(int position, Object JavaDoc value) {
135         if (position > paramEndIndex) {
136             paramEndIndex = position;
137         }
138         if (params.length == position) {
139             Object JavaDoc[] tmp = new Object JavaDoc[params.length + 1];
140             System.arraycopy(params, 0, tmp, 0, params.length);
141             params = tmp;
142         }
143         params[position] = value;
144         return this;
145     }
146
147     public Query setParameter(int position, Date value, TemporalType temporalType) {
148         setParameter(position, value);
149         return this;
150     }
151
152     public Query setParameter(int position, Calendar value, TemporalType temporalType) {
153         setParameter(position, value);
154         return this;
155     }
156
157     public Query setFlushMode(FlushModeType flushMode) {
158         setIgnoreCache(flushMode != FlushModeType.AUTO);
159         return this;
160     }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179     public void setBounded(boolean value) {
180         queryDetails.setBounded(value);
181     }
182
183     public boolean isBounded() {
184         return queryDetails.isBounded();
185     }
186
187     public void setClass(Class JavaDoc cls) {
188         changed();
189         queryDetails.setCandidateClass(cls);
190     }
191
192     public void setCandidates(Extent pcs) {
193         changed();
194         queryDetails.setExtent(pcs);
195     }
196
197     public void setCandidates(Collection pcs) {
198         changed();
199         queryDetails.setCol(pcs);
200     }
201
202     public void setFilter(String JavaDoc filter) {
203         changed();
204         queryDetails.setFilter(filter);
205     }
206
207     public String JavaDoc getFilter() {
208         return queryDetails.getFilter();
209     }
210
211     public void declareImports(String JavaDoc imports) {
212         changed();
213         queryDetails.setImports(imports);
214     }
215
216     public void declareParameters(String JavaDoc params) {
217         changed();
218         queryDetails.declareParameters(params);
219     }
220
221     public void declareVariables(String JavaDoc variables) {
222         changed();
223         queryDetails.setVariables(variables);
224     }
225
226     public void setOrdering(String JavaDoc ordering) {
227         changed();
228         queryDetails.setOrdering(ordering);
229     }
230
231     public void setIgnoreCache(boolean ignoreCache) {
232         changed();
233         queryDetails.setIgnoreCache(ignoreCache);
234     }
235
236     private EntityManagerImp getRealPM() {
237         if (pmProxy == null) {
238             throw BindingSupportImpl.getInstance().invalidOperation(
239                     "Query is not associated with a PersistenceManager");
240         }
241         return pmProxy.getEm();
242     }
243
244     public void setFetchGroup(String JavaDoc fgName) {
245         if (fgName == null) {
246             queryDetails.setFetchGroupIndex(0);
247             changed();
248             return;
249         } else {
250             if (queryDetails.getCandidateClass() == null) {
251                 throw BindingSupportImpl.getInstance().invalidOperation(
252                         "Please first supply a candidate class");
253             }
254             FetchGroup fg = getRealPM().modelMetaData.getClassMetaData(
255                     queryDetails.getCandidateClass()).getFetchGroup(fgName);
256             if (fg == null) {
257                 throw BindingSupportImpl.getInstance().invalidOperation("No fetchGroup with name "
258                         + fgName
259                         + " for class "
260                         + queryDetails.getCandidateClass().getName());
261             }
262
263             queryDetails.setFetchGroupIndex(fg.index);
264             changed();
265         }
266     }
267
268     public String JavaDoc getFetchGroup() {
269         int i = queryDetails.getFetchGroupIndex();
270         if (i == 0) return null;
271         ClassMetaData cmd = getRealPM().modelMetaData.getClassMetaData(
272                 queryDetails.getCandidateClass());
273         return cmd.fetchGroups[i].name;
274     }
275
276     public void setMaxRows(int amount) {
277         changed();
278         this.queryDetails.setMaxResultCount(amount);
279     }
280
281     public int getMaxRows() {
282         return queryDetails.getMaxResultCount();
283     }
284
285     public void setFetchSize(int value) {
286         changed();
287         this.queryDetails.setResultBatchSize(value);
288     }
289
290     public int getFetchSize() {
291         return queryDetails.getResultBatchSize();
292     }
293
294     public void setRandomAccess(boolean on) {
295         changed();
296         queryDetails.setRandomAccess(on);
297     }
298
299     public boolean isRandomAccess() {
300         return queryDetails.isRandomAccess();
301     }
302
303     public void setCountStarOnSize(boolean on) {
304         changed();
305         queryDetails.setCountOnSize(on);
306     }
307
308     public boolean isCountStarOnSize() {
309         return queryDetails.isCountOnSize();
310     }
311
312     public boolean getIgnoreCache() {
313         return queryDetails.isIgnoreCache();
314     }
315
316     public void setEvictionClasses(Class JavaDoc[] classes, boolean includeSubclasses) {
317         setEvictionClasses(getRealPM().modelMetaData.convertToClassIndexes(
318                 classes,
319                 includeSubclasses));
320     }
321
322     public void setEvictionClasses(int[] classIndexes) {
323         changed();
324         queryDetails.setExtraEvictClasses(classIndexes);
325     }
326
327     public Class JavaDoc[] getEvictionClasses() {
328         int[] a = queryDetails.getExtraEvictClasses();
329         return a == null ? null : getRealPM().modelMetaData.convertFromClassIndexes(
330                 a);
331     }
332
333     public void setResult(String JavaDoc result) {
334         changed();
335         queryDetails.setResult(result);
336     }
337
338     public void setGrouping(String JavaDoc grouping) {
339         changed();
340         queryDetails.setGrouping(grouping);
341     }
342
343     /**
344      * Specify that there is a single result of the query.
345      */

346     public void setUnique(boolean unique) {
347         changed();
348         queryDetails.setUnique(unique);
349     }
350
351     public void compile() {
352         if (compiledQuery == null) {
353             queryDetails.updateCounts();
354             compiledQuery = pmProxy.getEm().getStorageManager().compileQuery(
355                     queryDetails);
356         }
357     }
358
359     /**
360      * TODO: move to base class
361      * @param n
362      */

363     public void checkParamCount(int n) {
364         if (n != queryDetails.getTotalParamCount()) {
365             throw BindingSupportImpl.getInstance().runtime(
366                     "Expected " +
367                     queryDetails.getTotalParamCount() + " parameters, have " + n);
368         }
369     }
370
371     public Object JavaDoc execute() {
372         queryDetails.updateCounts();
373         return executeWithArrayImp(null);
374     }
375
376     public Object JavaDoc execute(Object JavaDoc p1) {
377         checkParamCount(1);
378         queryDetails.updateCounts();
379         if (queryDetails.hasJdoGenieOptions()) {
380             processJdoGenieOptions(p1);
381             return executeWithArrayImp(null);
382         } else {
383             return executeWithArrayImp(new Object JavaDoc[]{p1});
384         }
385     }
386
387     public Object JavaDoc execute(Object JavaDoc p1, Object JavaDoc p2) {
388         checkParamCount(2);
389         queryDetails.updateCounts();
390         switch (queryDetails.getOptionsParamIndex()) {
391             case 0:
392                 processJdoGenieOptions(p1);
393                 return executeWithArrayImp(new Object JavaDoc[]{p2});
394             case 1:
395                 processJdoGenieOptions(p2);
396                 return executeWithArrayImp(new Object JavaDoc[]{p1});
397         }
398         return executeWithArrayImp(new Object JavaDoc[]{p1, p2});
399     }
400
401     public Object JavaDoc execute(Object JavaDoc p1, Object JavaDoc p2, Object JavaDoc p3) {
402         checkParamCount(3);
403         queryDetails.updateCounts();
404         switch (queryDetails.getOptionsParamIndex()) {
405             case 0:
406                 processJdoGenieOptions(p1);
407                 return executeWithArrayImp(new Object JavaDoc[]{p2, p3});
408             case 1:
409                 processJdoGenieOptions(p2);
410                 return executeWithArrayImp(new Object JavaDoc[]{p1, p3});
411             case 2:
412                 processJdoGenieOptions(p2);
413                 return executeWithArrayImp(new Object JavaDoc[]{p1, p2});
414         }
415         ;
416         return executeWithArrayImp(new Object JavaDoc[]{p1, p2, p3});
417     }
418
419     public final Object JavaDoc executeWithArray(Object JavaDoc[] parameters) {
420         queryDetails.updateCounts();
421         int n = parameters == null ? 0 : parameters.length;
422         int oi = queryDetails.getOptionsParamIndex();
423         if (oi >= 0) {
424             processJdoGenieOptions(parameters[oi]);
425             if (n == 1) {
426                 return executeWithArrayImp(null);
427             }
428             Object JavaDoc[] a = new Object JavaDoc[n - 1];
429             if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi);
430             if (oi < n) System.arraycopy(parameters, oi + 1, a, oi, n - oi - 1);
431             return executeWithArrayImp(a);
432         } else {
433             return executeWithArrayImp(copyParams(parameters));
434         }
435     }
436
437     /**
438      * Get the query plan for this query. This will include the SQL and
439      * possibly also a query plan for the SQL from the database itself.
440      */

441     public VersantQueryPlan getPlan(Object JavaDoc[] parameters) {
442         queryDetails.updateCounts();
443         if (queryDetails.getCol() != null) {
444             throw BindingSupportImpl.getInstance().invalidOperation(
445                     "getPlan is not supported for queries executed against a collection");
446         }
447         int n = parameters == null ? 0 : parameters.length;
448         checkParamCount(n);
449         int oi = queryDetails.getOptionsParamIndex();
450         if (oi >= 0) {
451             processJdoGenieOptions(parameters[oi]);
452             if (n == 1) {
453                 return getPlanImp(null);
454             }
455             Object JavaDoc[] a = new Object JavaDoc[n - 1];
456             if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi);
457             if (oi < n) System.arraycopy(parameters, oi, a, oi - 1, n - oi - 1);
458             return getPlanImp(a);
459         } else {
460             return getPlanImp(parameters);
461         }
462     }
463
464     public Object JavaDoc executeWithMap(Map parameters) {
465         queryDetails.updateCounts();
466         int tp = queryDetails.getTotalParamCount();
467         if (parameters.size() != tp) {
468             throw BindingSupportImpl.getInstance().runtime(
469                     "The number of entries in the map (" + parameters.size() + ") " +
470                     "differs from the number of declared parameters (" + tp + ")");
471         }
472         if (tp == 0) return executeWithArrayImp(null);
473
474         // extract the normal parameters from the map in declaration order
475
Object JavaDoc[] pa;
476         int np = queryDetails.getParamCount();
477         if (np > 0) {
478             pa = new Object JavaDoc[np];
479             String JavaDoc[] names = queryDetails.getParamNames();
480             for (int i = 0; i < np; i++) {
481                 String JavaDoc name = names[i];
482                 if (!parameters.containsKey(name)) {
483                     throw BindingSupportImpl.getInstance().runtime(
484                             "Parameter '" + name + "' not found in map");
485                 }
486                 pa[i] = parameters.get(name);
487             }
488         } else {
489             pa = null;
490         }
491
492         // process the jdoGenieOptions parameter if required
493
if (queryDetails.hasJdoGenieOptions()) {
494             Object JavaDoc o = parameters.get(VersantQuery.VERSANT_OPTIONS);
495             if (o == null) o = parameters.get(VersantQuery.JDO_GENIE_OPTIONS);
496             processJdoGenieOptions(o);
497         }
498
499         // exec
500
return executeWithArrayImp(pa);
501     }
502
503     private void processJdoGenieOptions(Object JavaDoc o) {
504         // restore default values first
505
setFetchGroup(null);
506         setRandomAccess(false);
507
508         // now set properties
509
if (o == null) return;
510         if (!(o instanceof String JavaDoc)) {
511             throw BindingSupportImpl.getInstance().runtime("Invalid " +
512                     VersantQuery.VERSANT_OPTIONS + ": Expected String value: " +
513                     o.getClass());
514         }
515         String JavaDoc props = (String JavaDoc)o;
516         if (props.length() == 0) return;
517         try {
518             BeanUtils.parseProperties(props, this);
519         } catch (Exception JavaDoc e) {
520             throw BindingSupportImpl.getInstance().runtime(
521                     "Invalid " + VersantQuery.VERSANT_OPTIONS + ": " + e.getMessage(), e);
522         }
523     }
524
525     /**
526      * The parameters array must NOT contain the jdoGenieOptions.
527      */

528     private final Object JavaDoc executeWithArrayImp(Object JavaDoc[] parameters) {
529         final EMProxy pmProxy = this.pmProxy;
530         pmProxy.getEm().convertPcParamsToOID(parameters);
531
532         //Check if this should be a multi-part query
533
Class JavaDoc cls = queryDetails.getCandidateClass();
534         Class JavaDoc[] candidates = null;
535         if (cls != null) {
536             candidates = pmProxy.getEm().modelMetaData.getQueryCandidatesFor(cls);
537             if (candidates == null) {
538                 throw BindingSupportImpl.getInstance().unsupported("Queries for class '"
539                         + queryDetails.getCandidateClass() + "' is not supported");
540             }
541         }
542
543         if (candidates != null && candidates.length > 1) {
544             //create subQueries for all the candidates and compile it
545
queryDetails.updateCounts();
546             Set qResults = new HashSet();
547             for (int i = 0; i < candidates.length; i++) {
548                 Class JavaDoc candidate = candidates[i];
549
550                 QueryDetails qd = new QueryDetails(queryDetails);
551                 qd.setCandidateClass(candidate);
552
553                 CompiledQuery cq = this.pmProxy.getEm().getStorageManager().compileQuery(qd);
554                 QueryResult qr = getQueryResult(parameters, qd, cq, this.pmProxy);
555
556                 qResults.add(qr);
557             }
558             return new MultiPartQueryResult(qResults);
559         } else {
560             compile();
561
562             //is this a unique query
563
if (compiledQuery.isUnique()) {
564                 //must do immediately
565
return QueryResultBase.resolveRow(pmProxy.getAllQueryResults(
566                         compiledQuery,
567                         parameters).getUnique(),
568                         pmProxy);
569             } else {
570                 return getQueryResult(parameters, queryDetails, compiledQuery, this.pmProxy);
571             }
572         }
573     }
574
575     private static Object JavaDoc[] copyParams(Object JavaDoc[] parameters) {
576         Object JavaDoc[] params = null;
577         if (parameters != null) {
578             params = new Object JavaDoc[parameters.length];
579             for (int i = 0; i < params.length; i++) {
580                 params[i] = parameters[i];
581             }
582         }
583         return params;
584     }
585
586     private QueryResult getQueryResult(Object JavaDoc[] params,
587             QueryDetails queryDetails, CompiledQuery compiledQuery, EMProxy emProxy) {
588         QueryResult res = null;
589         boolean collectionQuery = queryDetails.getCol() != null;
590         boolean containsNewOID = containsNewOID(params);
591
592 // if (collectionQuery) {
593
// // query agains a collection in memory
594
//// res = new MemoryQueryResult(pmProxy,
595
//// queryDetails, createSMList(queryDetails.getCol(), pmProxy), params);
596
// } else if (containsNewOID && queryDetails.isIgnoreCache()) {
597
// // query agains a collection in memory with some new instances
598
// res = new MemoryQueryResult();
599
// } else if (queryDetails.isRandomAccess()) {
600
// // random access query against database
601
// res = new RandomAccessQueryResult(pmProxy,
602
// compiledQuery, params);
603
// } else {
604
// normal query against database
605
res = new ForwardEJBQueryResult(emProxy, queryDetails,
606                     compiledQuery, params);
607 // }
608
if (emProxy.getMultithreaded()) {
609             res = new SynchronizedQueryResult(emProxy, res);
610         }
611
612         addResults(res);
613         return res;
614     }
615
616     /**
617      * Add a set of results to this query.
618      */

619     private void addResults(QueryResult q) {
620         synchronized (pmProxy) {
621             if (resultList == null) {
622                 resultList = q;
623             } else {
624                 q.setNext(resultList);
625                 resultList.setPrev(q);
626                 resultList = q;
627             }
628         }
629     }
630
631     /**
632      * Remove a set of results from this query.
633      */

634     private void removeResults(QueryResult q) {
635         synchronized (pmProxy) {
636             if (resultList == q) { // at tail of list
637
resultList = q.getNext();
638                 if (resultList != null) resultList.setPrev(null);
639                 q.setNext(null);
640             } else {
641                 q.getPrev().setNext(q.getNext());
642                 if (q.getNext() != null) q.getNext().setPrev(q.getPrev());
643                 q.setNext(null);
644                 q.setPrev(null);
645             }
646         }
647     }
648
649     /**
650      * TODO must check not to try and do convertPcParams twice
651      * <p/>
652      * The parameters array must NOT contain the jdoGenieOptions.
653      */

654     private VersantQueryPlan getPlanImp(Object JavaDoc[] parameters) {
655         pmProxy.getEm().convertPcParamsToOID(parameters);
656         compile();
657         return pmProxy.getEm().getStorageManager().getQueryPlan(queryDetails,
658                 compiledQuery, parameters);
659     }
660
661     private static List createSMList(Collection col, PMProxy pmProxy) {
662         List tmpList = new ArrayList();
663         for (Iterator iterator = col.iterator(); iterator.hasNext();) {
664             PersistenceCapable persistenceCapable = (PersistenceCapable)iterator.next();
665             tmpList.add(pmProxy.getInternalSM(persistenceCapable));
666         }
667         return tmpList;
668     }
669
670     private static boolean containsNewOID(Object JavaDoc[] params) {
671         if (params != null) {
672             for (int i = 0; i < params.length; i++) {
673                 Object JavaDoc param = params[i];
674                 if (param instanceof NewObjectOID) {
675                     return true;
676                 }
677             }
678         }
679         return false;
680     }
681
682     public PersistenceManager getPersistenceManager() {
683         return pmProxy.getEm();
684     }
685
686     public void close(Object JavaDoc queryResult) {
687         QueryResult qr = (QueryResult)queryResult;
688         qr.close();
689         removeResults(qr);
690     }
691
692     public void closeAll() {
693         synchronized (pmProxy) {
694             if (resultList == null) return;
695             resultList.close();
696             for (QueryResult i = resultList.getNext(); i != null; i = i.getNext()) {
697                 i.close();
698                 i.getPrev().setNext(null);
699                 i.setPrev(null);
700             }
701             resultList = null;
702         }
703     }
704
705     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
706         queryDetails.writeExternal(out);
707     }
708
709     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc,
710             ClassNotFoundException JavaDoc {
711         QueryDetails qp = new QueryDetails();
712         qp.readExternal(in);
713         this.queryDetails.fillFrom(qp);
714     }
715
716     public void initialiseFrom(VersantEjbQueryImp clientQuery) {
717         this.queryDetails.fillFrom(clientQuery.queryDetails);
718         this.queryDetails.clearExtentAndCol();
719     }
720
721     public void setCacheable(boolean on) {
722         changed();
723         queryDetails.setCacheable(on);
724     }
725
726     public String JavaDoc getImports() {
727         return queryDetails.getImports();
728     }
729
730     public String JavaDoc getParameters() {
731         return queryDetails.getParameters();
732     }
733
734     public String JavaDoc getVariables() {
735         return queryDetails.getVariables();
736     }
737
738     public String JavaDoc getOrdering() {
739         return queryDetails.getOrdering();
740     }
741
742     public String JavaDoc getGrouping() {
743         return queryDetails.getGrouping();
744     }
745
746     public String JavaDoc getResult() {
747         return queryDetails.getResult();
748     }
749
750     public boolean isUnique() {
751         return queryDetails.getUnique() == QueryDetails.TRUE;
752     }
753 }
754
Popular Tags