001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo;
012:
013: import com.versant.core.common.QueryResultContainer;
014: import com.versant.core.server.CompiledQuery;
015: import com.versant.core.server.QueryResultWrapper;
016:
017: import java.util.*;
018: import java.lang.reflect.Array;
019:
020: import com.versant.core.common.BindingSupportImpl;
021:
022: /**
023: * This is used for the results of queries executed with randomAccess=true.
024: * It provides fully random access to the List of results using a scrollable
025: * ResultSet on the server side.
026: */
027: public final class RandomAccessQueryResult extends QueryResultBase {
028:
029: private QueryResultWrapper qrsIF;
030: private PMProxy pmProxy;
031: private final CompiledQuery compiledQuery;
032: private Object[] params;
033: private List openQIters = new ArrayList();
034: private int size = -1;
035: private int fetchAmount;
036:
037: private Object[] window;
038: private int absoluteIndexStart = -1;
039: private int windowSize;
040:
041: public RandomAccessQueryResult(PMProxy pm,
042: CompiledQuery compiledQuery, Object[] params) {
043: this .pmProxy = pm;
044: this .compiledQuery = compiledQuery;
045: qrsIF = pmProxy.executeQuery(compiledQuery, params);
046: if (!compiledQuery.getQueryDetails().isIgnoreCache()) {
047: pmProxy.flushIfDepOn(compiledQuery.getEvictionClassBits());
048: }
049: this .params = params;
050: fetchAmount = compiledQuery.getQueryDetails()
051: .getResultBatchSize();
052: }
053:
054: public void setParams(Object[] params) {
055: this .params = params;
056: }
057:
058: private void checkClosed() {
059: if (qrsIF == null) {
060: throw BindingSupportImpl.getInstance().invalidOperation(
061: "Query result has been closed");
062: }
063: }
064:
065: public void setBatchFetchSize(int amount) {
066: if (amount < 1) {
067: throw BindingSupportImpl.getInstance().invalidOperation(
068: "'FetchSize of '" + amount + " is invalid");
069: }
070: fetchAmount = amount;
071: }
072:
073: public Object get(int index) {
074: checkClosed();
075: if (index < 0) {
076: throw BindingSupportImpl.getInstance().invalidOperation(
077: "Index must be greater or equal to '0'");
078: }
079:
080: if (index < absoluteIndexStart) {
081: //before current window
082:
083: QueryResultContainer container = null;
084: synchronized (pmProxy) {
085: container = pmProxy.getAbsolute(qrsIF, index,
086: fetchAmount);
087: pmProxy.addToCache(container.container);
088: }
089:
090: window = container.getDataArray();
091: absoluteIndexStart = index;
092: windowSize = container.size();
093:
094: container.reset();
095: } else if (index > absoluteIndexStart) {
096: //might be in window
097: int absoluteIndexEnd = ((absoluteIndexStart + windowSize) - 1);
098: if (index > absoluteIndexEnd) {
099: //after window
100: QueryResultContainer container = pmProxy.getAbsolute(
101: qrsIF, index, fetchAmount);
102: pmProxy.addToCache(container.container);
103:
104: window = container.getDataArray();
105: absoluteIndexStart = index;
106: windowSize = container.size();
107:
108: container.reset();
109: }
110: }
111:
112: if (windowSize == 0) {
113: throw BindingSupportImpl.getInstance()
114: .arrayIndexOutOfBounds(
115: "index '" + index + "' is too big");
116: }
117: return resolveRow(window[index - absoluteIndexStart], pmProxy);
118: }
119:
120: /**
121: * @return
122: */
123: public int size() {
124: if (size == -1) {
125: checkClosed();
126: size = pmProxy.getResultCount(qrsIF);
127: }
128: return size;
129: }
130:
131: public boolean isEmpty() {
132: return size() > 0;
133: }
134:
135: private RuntimeException createUseNonRandomAccessException() {
136: return BindingSupportImpl.getInstance().invalidOperation(
137: "Method not available for a randomAccess=true query");
138: }
139:
140: public boolean contains(Object o) {
141: throw createUseNonRandomAccessException();
142: }
143:
144: public Object[] toArray() {
145: if (!compiledQuery.getQueryDetails().isIgnoreCache()) {
146: pmProxy.flushIfDepOn(compiledQuery.getEvictionClassBits());
147: }
148:
149: QueryResultContainer qContainer = pmProxy.getAllQueryResults(
150: compiledQuery, params);
151: pmProxy.addToCache(qContainer.container);
152:
153: Object[] resolvedData = qContainer.toResolvedObject(pmProxy);
154: int n = qContainer.size();
155: Object[] a = new Object[n];
156: for (int i = 0; i < n; i++) {
157: a[i] = resolvedData[i];
158: }
159: return a;
160: }
161:
162: public Object[] toArray(Object a[]) {
163: if (a == null)
164: throw new NullPointerException("The supplied array is null");
165:
166: if (!compiledQuery.getQueryDetails().isIgnoreCache()) {
167: pmProxy.flushIfDepOn(compiledQuery.getEvictionClassBits());
168: }
169:
170: QueryResultContainer qContainer = pmProxy.getAllQueryResults(
171: compiledQuery, params);
172: pmProxy.addToCache(qContainer.container);
173:
174: Object[] resolvedData = qContainer.toResolvedObject(pmProxy);
175: int n = qContainer.size();
176: if (n > a.length) {
177: a = (Object[]) Array.newInstance(a.getClass()
178: .getComponentType(), n);
179: }
180:
181: for (int i = 0; i < n; i++) {
182: a[i] = resolvedData[i];
183: }
184: return a;
185: }
186:
187: public boolean containsAll(Collection c) {
188: throw createUseNonRandomAccessException();
189: }
190:
191: public int indexOf(Object o) {
192: throw createUseNonRandomAccessException();
193: }
194:
195: public int lastIndexOf(Object o) {
196: throw createUseNonRandomAccessException();
197: }
198:
199: public Iterator iterator() {
200: return createInternalIter();
201: }
202:
203: public ListIterator listIterator() {
204: return createInternalIter();
205: }
206:
207: public ListIterator listIterator(int index) {
208: throw BindingSupportImpl.getInstance().unsupported(null);
209: }
210:
211: public List subList(int fromIndex, int toIndex) {
212: checkClosed();
213: QueryResultContainer container = null;
214: final int toAdd = toIndex - fromIndex;
215: if (toAdd <= 0) {
216: return new ArrayList();
217: }
218: final List list = new ArrayList(toAdd);
219: container = pmProxy.getAbsolute(qrsIF, fromIndex, toAdd);
220:
221: //provide it for instanceCache
222: pmProxy.addToCache(container.container);
223:
224: container.resolveAndAddTo(list, pmProxy);
225: container.reset();
226: return list;
227: }
228:
229: private ListIterator createInternalIter() {
230: return createInternalIterImp(false);
231: }
232:
233: private ListIterator createInternalIterImp(boolean doNotFlush) {
234: checkClosed();
235: QueryIterator queryIterator = new QueryIterator(pmProxy,
236: compiledQuery, params, doNotFlush);
237: openQIters.add(queryIterator);
238: return queryIterator;
239: }
240:
241: public Iterator createInternalIterNoFlush() {
242: return createInternalIterImp(true);
243: }
244:
245: public void close() {
246: for (int i = 0; i < openQIters.size(); i++) {
247: ((JDOListIterator) openQIters.get(i)).close();
248: }
249: openQIters.clear();
250:
251: if (qrsIF != null) {
252: pmProxy.closeQuery(qrsIF);
253: qrsIF = null;
254: }
255:
256: window = null;
257: }
258:
259: }
|