001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.jdbc.sql;
020:
021: import java.io.InputStream;
022: import java.io.Reader;
023: import java.math.BigDecimal;
024: import java.math.BigInteger;
025: import java.sql.Array;
026: import java.sql.Blob;
027: import java.sql.Clob;
028: import java.sql.Ref;
029: import java.sql.SQLException;
030: import java.sql.Time;
031: import java.sql.Timestamp;
032: import java.util.Calendar;
033: import java.util.Comparator;
034: import java.util.Date;
035: import java.util.Locale;
036: import java.util.Map;
037:
038: import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
039: import org.apache.openjpa.jdbc.kernel.JDBCStore;
040: import org.apache.openjpa.jdbc.meta.ClassMapping;
041: import org.apache.openjpa.jdbc.meta.FieldMapping;
042: import org.apache.openjpa.jdbc.schema.Column;
043: import org.apache.openjpa.util.UnsupportedException;
044:
045: /**
046: * Result that merges multiple result delegates. Support exists for
047: * maintaining ordering of the internally-held results, provided that each
048: * of the individual results is itself ordered.
049: *
050: * @author Abe White
051: */
052: public class MergedResult implements Result {
053:
054: private static final byte NEXT = 0;
055: private static final byte CURRENT = 1;
056: private static final byte DONE = 2;
057:
058: private final Result[] _res;
059: private final byte[] _status;
060: private final ResultComparator _comp;
061: private final Object[] _order;
062: private int _idx = 0;
063: private boolean _pushedBack = false;
064:
065: /**
066: * Constructor; supply delegates.
067: */
068: public MergedResult(Result[] res) {
069: this (res, null);
070: }
071:
072: /**
073: * Constructor; supply delegates and comparator for ordering results.
074: */
075: public MergedResult(Result[] res, ResultComparator comp) {
076: _res = res;
077: _comp = comp;
078: _order = (comp == null) ? null : new Object[res.length];
079: _status = (comp == null) ? null : new byte[res.length];
080: }
081:
082: public Object getEager(FieldMapping key) {
083: return _res[_idx].getEager(key);
084: }
085:
086: public void putEager(FieldMapping key, Object res) {
087: _res[_idx].putEager(key, res);
088: }
089:
090: public Joins newJoins() {
091: return _res[_idx].newJoins();
092: }
093:
094: public void close() {
095: for (int i = 0; i < _res.length; i++)
096: _res[i].close();
097: }
098:
099: public boolean isLocking() {
100: return _res[_idx].isLocking();
101: }
102:
103: public boolean supportsRandomAccess() throws SQLException {
104: return false;
105: }
106:
107: public boolean absolute(int row) throws SQLException {
108: throw new UnsupportedException();
109: }
110:
111: public boolean next() throws SQLException {
112: if (_pushedBack) {
113: _pushedBack = false;
114: return true;
115: }
116:
117: if (_comp == null) {
118: while (!_res[_idx].next()) {
119: if (_idx == _res.length - 1)
120: return false;
121: _idx++;
122: }
123: return true;
124: }
125:
126: // ordering is involved; extract order values from each result
127: boolean hasValue = false;
128: for (int i = 0; i < _status.length; i++) {
129: switch (_status[i]) {
130: case NEXT:
131: if (_res[i].next()) {
132: hasValue = true;
133: _status[i] = CURRENT;
134: _order[i] = _comp.getOrderingValue(_res[i], i);
135: } else
136: _status[i] = DONE;
137: break;
138: case CURRENT:
139: hasValue = true;
140: break;
141: }
142: }
143:
144: // all results exhausted
145: if (!hasValue)
146: return false;
147:
148: // for all results with values, find the 'least' one according to
149: // the comparator
150: int least = -1;
151: Object orderVal = null;
152: for (int i = 0; i < _order.length; i++) {
153: if (_status[i] != CURRENT)
154: continue;
155: if (least == -1 || _comp.compare(_order[i], orderVal) < 0) {
156: least = i;
157: orderVal = _order[i];
158: }
159: }
160:
161: // make the current result the one with the least value, and clear
162: // the cached value for that result
163: _idx = least;
164: _order[least] = null;
165: _status[least] = NEXT;
166: return true;
167: }
168:
169: public void pushBack() throws SQLException {
170: _pushedBack = true;
171: }
172:
173: public int size() throws SQLException {
174: int size = 0;
175: for (int i = 0; i < _res.length; i++)
176: size += _res[i].size();
177: return size;
178: }
179:
180: public boolean contains(Object obj) throws SQLException {
181: return _res[_idx].contains(obj);
182: }
183:
184: public boolean containsAll(Object[] objs) throws SQLException {
185: return _res[_idx].containsAll(objs);
186: }
187:
188: public boolean contains(Column col, Joins joins)
189: throws SQLException {
190: return _res[_idx].contains(col, joins);
191: }
192:
193: public boolean containsAll(Column[] cols, Joins joins)
194: throws SQLException {
195: return _res[_idx].containsAll(cols, joins);
196: }
197:
198: public ClassMapping getBaseMapping() {
199: return _res[_idx].getBaseMapping();
200: }
201:
202: public void setBaseMapping(ClassMapping mapping) {
203: _res[_idx].setBaseMapping(mapping);
204: }
205:
206: public int indexOf() {
207: return _res[_idx].indexOf();
208: }
209:
210: public Object load(ClassMapping mapping, JDBCStore store,
211: JDBCFetchConfiguration fetch) throws SQLException {
212: return _res[_idx].load(mapping, store, fetch);
213: }
214:
215: public Object load(ClassMapping mapping, JDBCStore store,
216: JDBCFetchConfiguration fetch, Joins joins)
217: throws SQLException {
218: return _res[_idx].load(mapping, store, fetch, joins);
219: }
220:
221: public Array getArray(Object obj) throws SQLException {
222: return _res[_idx].getArray(obj);
223: }
224:
225: public InputStream getAsciiStream(Object obj) throws SQLException {
226: return _res[_idx].getAsciiStream(obj);
227: }
228:
229: public BigDecimal getBigDecimal(Object obj) throws SQLException {
230: return _res[_idx].getBigDecimal(obj);
231: }
232:
233: public BigInteger getBigInteger(Object obj) throws SQLException {
234: return _res[_idx].getBigInteger(obj);
235: }
236:
237: public InputStream getBinaryStream(Object obj) throws SQLException {
238: return _res[_idx].getBinaryStream(obj);
239: }
240:
241: public Blob getBlob(Object obj) throws SQLException {
242: return _res[_idx].getBlob(obj);
243: }
244:
245: public boolean getBoolean(Object obj) throws SQLException {
246: return _res[_idx].getBoolean(obj);
247: }
248:
249: public byte getByte(Object obj) throws SQLException {
250: return _res[_idx].getByte(obj);
251: }
252:
253: public byte[] getBytes(Object obj) throws SQLException {
254: return _res[_idx].getBytes(obj);
255: }
256:
257: public Calendar getCalendar(Object obj) throws SQLException {
258: return _res[_idx].getCalendar(obj);
259: }
260:
261: public char getChar(Object obj) throws SQLException {
262: return _res[_idx].getChar(obj);
263: }
264:
265: public Reader getCharacterStream(Object obj) throws SQLException {
266: return _res[_idx].getCharacterStream(obj);
267: }
268:
269: public Clob getClob(Object obj) throws SQLException {
270: return _res[_idx].getClob(obj);
271: }
272:
273: public Date getDate(Object obj) throws SQLException {
274: return _res[_idx].getDate(obj);
275: }
276:
277: public java.sql.Date getDate(Object obj, Calendar cal)
278: throws SQLException {
279: return _res[_idx].getDate(obj, cal);
280: }
281:
282: public double getDouble(Object obj) throws SQLException {
283: return _res[_idx].getDouble(obj);
284: }
285:
286: public float getFloat(Object obj) throws SQLException {
287: return _res[_idx].getFloat(obj);
288: }
289:
290: public int getInt(Object obj) throws SQLException {
291: return _res[_idx].getInt(obj);
292: }
293:
294: public Locale getLocale(Object obj) throws SQLException {
295: return _res[_idx].getLocale(obj);
296: }
297:
298: public long getLong(Object obj) throws SQLException {
299: return _res[_idx].getLong(obj);
300: }
301:
302: public Number getNumber(Object obj) throws SQLException {
303: return _res[_idx].getNumber(obj);
304: }
305:
306: public Object getObject(Object obj, int metaType, Object arg)
307: throws SQLException {
308: return _res[_idx].getObject(obj, metaType, arg);
309: }
310:
311: public Object getSQLObject(Object obj, Map map) throws SQLException {
312: return _res[_idx].getSQLObject(obj, map);
313: }
314:
315: public Ref getRef(Object obj, Map map) throws SQLException {
316: return _res[_idx].getRef(obj, map);
317: }
318:
319: public short getShort(Object obj) throws SQLException {
320: return _res[_idx].getShort(obj);
321: }
322:
323: public String getString(Object obj) throws SQLException {
324: return _res[_idx].getString(obj);
325: }
326:
327: public Time getTime(Object obj, Calendar cal) throws SQLException {
328: return _res[_idx].getTime(obj, cal);
329: }
330:
331: public Timestamp getTimestamp(Object obj, Calendar cal)
332: throws SQLException {
333: return _res[_idx].getTimestamp(obj, cal);
334: }
335:
336: public Array getArray(Column col, Joins joins) throws SQLException {
337: return _res[_idx].getArray(col, joins);
338: }
339:
340: public InputStream getAsciiStream(Column col, Joins joins)
341: throws SQLException {
342: return _res[_idx].getAsciiStream(col, joins);
343: }
344:
345: public BigDecimal getBigDecimal(Column col, Joins joins)
346: throws SQLException {
347: return _res[_idx].getBigDecimal(col, joins);
348: }
349:
350: public BigInteger getBigInteger(Column col, Joins joins)
351: throws SQLException {
352: return _res[_idx].getBigInteger(col, joins);
353: }
354:
355: public InputStream getBinaryStream(Column col, Joins joins)
356: throws SQLException {
357: return _res[_idx].getBinaryStream(col, joins);
358: }
359:
360: public Blob getBlob(Column col, Joins joins) throws SQLException {
361: return _res[_idx].getBlob(col, joins);
362: }
363:
364: public boolean getBoolean(Column col, Joins joins)
365: throws SQLException {
366: return _res[_idx].getBoolean(col, joins);
367: }
368:
369: public byte getByte(Column col, Joins joins) throws SQLException {
370: return _res[_idx].getByte(col, joins);
371: }
372:
373: public byte[] getBytes(Column col, Joins joins) throws SQLException {
374: return _res[_idx].getBytes(col, joins);
375: }
376:
377: public Calendar getCalendar(Column col, Joins joins)
378: throws SQLException {
379: return _res[_idx].getCalendar(col, joins);
380: }
381:
382: public char getChar(Column col, Joins joins) throws SQLException {
383: return _res[_idx].getChar(col, joins);
384: }
385:
386: public Reader getCharacterStream(Column col, Joins joins)
387: throws SQLException {
388: return _res[_idx].getCharacterStream(col, joins);
389: }
390:
391: public Clob getClob(Column col, Joins joins) throws SQLException {
392: return _res[_idx].getClob(col, joins);
393: }
394:
395: public Date getDate(Column col, Joins joins) throws SQLException {
396: return _res[_idx].getDate(col, joins);
397: }
398:
399: public java.sql.Date getDate(Column col, Calendar cal, Joins joins)
400: throws SQLException {
401: return _res[_idx].getDate(col, cal, joins);
402: }
403:
404: public double getDouble(Column col, Joins joins)
405: throws SQLException {
406: return _res[_idx].getDouble(col, joins);
407: }
408:
409: public float getFloat(Column col, Joins joins) throws SQLException {
410: return _res[_idx].getFloat(col, joins);
411: }
412:
413: public int getInt(Column col, Joins joins) throws SQLException {
414: return _res[_idx].getInt(col, joins);
415: }
416:
417: public Locale getLocale(Column col, Joins joins)
418: throws SQLException {
419: return _res[_idx].getLocale(col, joins);
420: }
421:
422: public long getLong(Column col, Joins joins) throws SQLException {
423: return _res[_idx].getLong(col, joins);
424: }
425:
426: public Number getNumber(Column col, Joins joins)
427: throws SQLException {
428: return _res[_idx].getNumber(col, joins);
429: }
430:
431: public Object getObject(Column col, Object arg, Joins joins)
432: throws SQLException {
433: return _res[_idx].getObject(col, arg, joins);
434: }
435:
436: public Object getSQLObject(Column col, Map map, Joins joins)
437: throws SQLException {
438: return _res[_idx].getSQLObject(col, map, joins);
439: }
440:
441: public Ref getRef(Column col, Map map, Joins joins)
442: throws SQLException {
443: return _res[_idx].getRef(col, map, joins);
444: }
445:
446: public short getShort(Column col, Joins joins) throws SQLException {
447: return _res[_idx].getShort(col, joins);
448: }
449:
450: public String getString(Column col, Joins joins)
451: throws SQLException {
452: return _res[_idx].getString(col, joins);
453: }
454:
455: public Time getTime(Column col, Calendar cal, Joins joins)
456: throws SQLException {
457: return _res[_idx].getTime(col, cal, joins);
458: }
459:
460: public Timestamp getTimestamp(Column col, Calendar cal, Joins joins)
461: throws SQLException {
462: return _res[_idx].getTimestamp(col, cal, joins);
463: }
464:
465: public boolean wasNull() throws SQLException {
466: return _res[_idx].wasNull();
467: }
468:
469: public void startDataRequest(Object mapping) {
470: for (int i = 0; i < _res.length; i++)
471: _res[i].startDataRequest(mapping);
472: }
473:
474: public void endDataRequest() {
475: for (int i = 0; i < _res.length; i++)
476: _res[i].endDataRequest();
477: }
478:
479: /**
480: * Comparator for ordering result rows.
481: */
482: public static interface ResultComparator extends Comparator {
483:
484: /**
485: * Return the ordering value of the current row of the given result.
486: */
487: public Object getOrderingValue(Result res, int idx);
488: }
489: }
|