KickJava   Java API By Example, From Geeks To Geeks.

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


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.PCList;
15 import com.versant.core.common.QueryResultContainer;
16 import com.versant.core.server.CompiledQuery;
17 import com.versant.core.server.QueryResultWrapper;
18
19 import java.io.Serializable JavaDoc;
20 import java.util.*;
21
22 import com.versant.core.common.BindingSupportImpl;
23 import com.versant.core.jdo.*;
24
25 /**
26  * Forward only access to the results of a Query. This will rerieve all results
27  * if any method requiring access to all results is called (e.g. size).
28  * Otherwise it retrieves elements in batches.
29  *
30  * @see com.versant.core.jdo.QueryResult
31  */

32 public final class ForwardEJBQueryResult extends QueryResultBase
33         implements Serializable JavaDoc {
34
35     /**
36      * Nothing has happened as such and hence anything is allowed at this stage.
37      */

38     private static final int STATUS_NON_INITIALISED = 0;
39     /**
40      * Implies that the results have been resolved fully and get's and iterators is allowed.
41      */

42     private static final int STATUS_RESOLVED = 1;
43     /**
44      * Implies that a get was called and hence no iterators may be created
45      */

46     private static final int STATUS_SPARSE = 2;
47     /**
48      * Implies that the query has been closed.
49      */

50     private static final int STATUS_CLOSED = 3;
51     /**
52      * The current status.
53      */

54     private int status;
55
56     /**
57      * The size if it has been computed. This depends on the state.
58      */

59     private int size;
60     /**
61      * If this is a countOnSize query? We only do a count once and then clear
62      * the flag so more size() calls will resolve the results.
63      */

64     private boolean countOnSize;
65     private PCList backingArray;
66
67     private final EMProxy pm;
68     /**
69      * The params that was passed for query execution.
70      */

71     private Object JavaDoc[] params;
72     private final List openWrapperIters = new ArrayList();
73
74     private final QueryDetails queryDetails;
75     private final CompiledQuery compiledQuery;
76
77     /**
78      * Fields used to implement a window in the resultset
79      */

80     private Object JavaDoc[] window;
81     private int windowSize;
82     private boolean noMoreDataInResultSet;
83
84     private int index;
85     private int maxAvailableIndex = -1;
86     private QueryResultWrapper qrw;
87
88     public ForwardEJBQueryResult(EMProxy pmProxy, QueryDetails queryDetails,
89             CompiledQuery compiledQuery, Object JavaDoc[] params) {
90         this.pm = pmProxy;
91         this.queryDetails = queryDetails;
92         this.compiledQuery = compiledQuery;
93         this.setParams(params);
94         countOnSize = queryDetails.isCountOnSize();
95     }
96
97     /**
98      * Is our compiledQuery the same as the one for qc?
99      */

100     public boolean isCompiledQueryEqual(ForwardEJBQueryResult qc) {
101         return compiledQuery.equals(qc.compiledQuery);
102     }
103
104     public void setParams(Object JavaDoc[] params) {
105         this.params = params;
106     }
107
108     /**
109      * Close all the open iterator's.
110      */

111     public void close() {
112         if (status == STATUS_CLOSED) return;
113
114         if (qrw != null) {
115             pm.closeQuery(qrw);
116             qrw = null;
117         }
118         window = null;
119
120         backingArray = null;
121         for (int i = 0; i < openWrapperIters.size(); i++) {
122             ((JDOListIterator)openWrapperIters.get(i)).close();
123         }
124         openWrapperIters.clear();
125         status = STATUS_CLOSED;
126     }
127
128     /**
129      * All the results will be resolved and the size returned. If this is already been called the the size will just
130      * be returned.
131      */

132     public int size() {
133         if (status != STATUS_RESOLVED) {
134             if (countOnSize) {
135                 countOnSize = false;
136                 return countRows();
137             } else {
138                 resolve();
139             }
140         }
141         return size;
142     }
143
144     public boolean isEmpty() {
145         if (status != STATUS_RESOLVED) {
146             resolve();
147         }
148         return backingArray.isEmpty();
149     }
150
151     public boolean contains(Object JavaDoc o) {
152         if (status != STATUS_RESOLVED) {
153             resolve();
154         }
155         return backingArray.contains(o);
156     }
157
158     public Iterator iterator() {
159         checkClosed();
160         Iterator result = null;
161         if (status == STATUS_RESOLVED) {
162             result = getLocalIter();
163         } else {
164             result = createInternalIter();
165         }
166         return result;
167     }
168
169     /**
170      * This is an iterator over the already fully resolved list.
171      *
172      * @see #backingArray
173      */

174     private ListIterator getLocalIter() {
175         ListIterator lIter = backingArray.listIterator();
176         openWrapperIters.add(lIter);
177         return lIter;
178     }
179
180     /**
181      * This executes a new server side query.
182      *
183      * @see com.versant.core.jdo.QueryResultIterator
184      */

185     private ListIterator createInternalIter() {
186         return createInternalIterImp(false);
187     }
188
189     private ListIterator createInternalIterImp(boolean doNotFlush) {
190         checkClosed();
191         EJBQueryIterator queryIterator = new EJBQueryIterator(pm, compiledQuery, params, doNotFlush);
192         openWrapperIters.add(queryIterator);
193         return queryIterator;
194     }
195
196     public Iterator createInternalIterNoFlush() {
197         return createInternalIterImp(true);
198     }
199
200     public ListIterator listIterator() {
201         return (ListIterator)iterator();
202     }
203
204     public ListIterator listIterator(int index) {
205         throw BindingSupportImpl.getInstance().notImplemented("");
206     }
207
208     /**
209      * Resolves all the data and add it to array.
210      */

211     public Object JavaDoc[] toArray() {
212         toArrayImp();
213         return backingArray.toArray();
214     }
215
216     public Object JavaDoc[] toArray(Object JavaDoc[] a) {
217         toArrayImp();
218         return backingArray.toArray(a);
219     }
220
221     private void toArrayImp() {
222         if (status != STATUS_RESOLVED) {
223             resolve();
224         }
225     }
226
227     private void resolve() {
228         if (status == STATUS_RESOLVED) return;
229         checkClosed();
230         if (status == STATUS_SPARSE) {
231             throw BindingSupportImpl.getInstance().invalidOperation(
232                     "Any operation that will fully resolve" +
233                     " the query may not be called once a 'get' operation was performed");
234         }
235
236         if (!queryDetails.isIgnoreCache()) {
237             pm.flushIfDepOn(compiledQuery.getEvictionClassBits());
238         }
239
240         QueryResultContainer qContainer = pm.getAllQueryResults(
241                 compiledQuery, params);
242         pm.addToCache(qContainer.container);
243
244         backingArray = new PCList(qContainer.toResolvedObject(pm), 0,
245                 qContainer.size());
246         size = backingArray.size();
247         status = STATUS_RESOLVED;
248         qContainer.reset();
249         pm.processLocalCacheReferenceQueue();
250     }
251
252     private void checkClosed() {
253         if (status == STATUS_CLOSED) {
254             throw BindingSupportImpl.getInstance().invalidOperation("Query result has been closed");
255         }
256     }
257
258     /**
259      * Execute the query in count(*) mode (countOnSize option).
260      */

261     private int countRows() {
262         checkClosed();
263         if (!queryDetails.isIgnoreCache()) {
264             pm.flushIfDepOn(compiledQuery.getEvictionClassBits());
265         }
266         return pm.getQueryRowCount(compiledQuery, params);
267     }
268
269     /**
270      * If the backingArray exist then the get should operate on it.
271      */

272     public Object JavaDoc get(int index) {
273         if (index < 0) {
274             throw BindingSupportImpl.getInstance().illegalArgument(
275                     "Index smaller than zero is not allowed");
276         }
277         Object JavaDoc result = null;
278         switch (status) {
279             case STATUS_RESOLVED:
280                 result = backingArray.get(index);
281                 break;
282             case STATUS_SPARSE:
283                 result = internalGet(index, maxAvailableIndex);
284                 break;
285             case STATUS_NON_INITIALISED:
286                 if (queryDetails.prefetchAll()) {
287                     resolve();
288                     result = backingArray.get(index);
289                 } else {
290                     if (!queryDetails.isIgnoreCache()) {
291                         pm.flushIfDepOn(compiledQuery.getEvictionClassBits());
292                     }
293
294                     QueryResultWrapper qrsIF =
295                             this.pm.executeQuery(compiledQuery, params);
296                     QueryResultContainer qContainer =
297                             this.pm.getNextQueryResult(qrsIF, index);
298
299
300                     if (qContainer.allResults) {
301                         pm.addToCache(qContainer.container);
302
303                         status = STATUS_RESOLVED;
304                         backingArray = new PCList(qContainer.toResolvedObject(pm), 0,
305                                 qContainer.size());
306                         size = backingArray.size();
307                         status = STATUS_RESOLVED;
308
309                         qContainer.reset();
310                         result = backingArray.get(index);
311                         pm.processLocalCacheReferenceQueue();
312                     } else {
313                         status = STATUS_SPARSE;
314                         qrw = qrsIF;
315                         addNewData(qContainer, index);
316                         result = internalGet(index, maxAvailableIndex);
317                     }
318                 }
319                 break;
320             default:
321                 checkClosed();
322                 throw BindingSupportImpl.getInstance().internal(
323                         "Status does not exist. Status = '" + status + "'");
324         }
325         return result;
326     }
327
328     private Object JavaDoc internalGet(int requestedIndex, final int maxAvailableIndex) {
329         if (requestedIndex > maxAvailableIndex && !noMoreDataInResultSet) {
330             getMoreData(requestedIndex);
331             return getNextData(0);
332         } else {
333             return getNextData(windowSize - ((maxAvailableIndex - requestedIndex) + 1));
334         }
335
336     }
337
338     private Object JavaDoc getNextData(int windowIndex) {
339         if (windowIndex == windowSize)
340             throw BindingSupportImpl.getInstance().arrayIndexOutOfBounds("index '"
341                     + index + "' is too big");
342
343         if (windowIndex < 0) {
344             throw BindingSupportImpl.getInstance().unsupported(
345                     "May only request index greater than the previously requested index." +
346                     "\nIf this is required then use VersantQuery.setRandomAccess.");
347         }
348
349         Object JavaDoc result = QueryResultBase.resolveRow(window[windowIndex], pm);
350         window[windowIndex] = null;
351         return result;
352     }
353
354     private void getMoreData(int requestedIndex) {
355         //get data from server
356
addNewData(pm.getNextQueryResult(qrw, requestedIndex - maxAvailableIndex - 1), requestedIndex);
357     }
358
359     private void addNewData(QueryResultContainer container, int requestedIndex) {
360         pm.addToCache(container.container);
361
362         window = container.getDataArray();
363         windowSize = container.size();
364         noMoreDataInResultSet = container.isqFinished();
365
366         index = requestedIndex;
367         maxAvailableIndex = index + windowSize - 1;
368         container.reset();
369     }
370
371     public int indexOf(Object JavaDoc o) {
372         if (status != STATUS_RESOLVED) {
373             resolve();
374         }
375         return backingArray.indexOf(o);
376     }
377
378     public int lastIndexOf(Object JavaDoc o) {
379         if (status != STATUS_RESOLVED) {
380             resolve();
381         }
382         return backingArray.lastIndexOf(o);
383     }
384
385     public List subList(int fromIndex, int toIndex) {
386         if (status != STATUS_RESOLVED) {
387             resolve();
388         }
389         return backingArray.subList(fromIndex, toIndex);
390     }
391
392     public boolean containsAll(Collection c) {
393         if (status != STATUS_RESOLVED) {
394             resolve();
395         }
396         return backingArray.containsAll(c);
397     }
398
399     public boolean equals(Object JavaDoc obj) {
400         if (status != STATUS_RESOLVED) {
401             resolve();
402         }
403         return backingArray.equals(obj);
404     }
405
406     public String JavaDoc toString() {
407         if (status != STATUS_RESOLVED) {
408             resolve();
409         }
410         return backingArray.toString();
411     }
412
413     /**
414      * Serialize out an ArrayList instead of ourselves.
415      */

416     public Object JavaDoc writeReplace() {
417         return new ArrayList(this);
418     }
419
420 }
421
Popular Tags