001: package org.apache.ojb.broker.accesslayer;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.util.ArrayList;
019: import java.util.Iterator;
020: import java.util.List;
021:
022: import org.apache.ojb.broker.PersistenceBrokerException;
023:
024: /**
025: * @author matthew.baird (mattbaird@yahoo.com)
026: *
027: * The ChainingIterator is an extent aware Iterator.
028: *
029: * How the ChainingIterator works:
030: * The ChainedIterator holds a collection of RsIterators for each queried
031: * Interface-based extent.
032: *
033: * The RsIterator is able to load objects that are non-interface extents,
034: * mapped to the same table.
035: *
036: * The ChainingIterator cannot return sorted results as the iterator is a
037: * collection of query results across different tables.
038: *
039: * @version $Id: ChainingIterator.java,v 1.13.2.2 2005/12/21 22:22:58 tomdz Exp $
040: */
041: public class ChainingIterator implements OJBIterator {
042: private List m_rsIterators = new ArrayList();
043: private OJBIterator m_activeIterator = null;
044:
045: /**
046: * The following are used to maintain an index of where
047: * the cursor is in the array of rsiterators. We do this
048: * because we can't find the position through the interface,
049: * and we need the position in order to support the relative(x)
050: * calls
051: */
052: private int m_activeIteratorIndex = 0;
053: private int m_fullSize = -1;
054: private int m_currentCursorPosition = 0;
055: /** if true do not fire PBLifeCycleEvent. */
056: private boolean disableLifeCycleEvents = false;
057:
058: /**
059: * Constructor for ChainingIterator.
060: */
061: public ChainingIterator() {
062: super ();
063: }
064:
065: /**
066: * Constructor for ChainingIterator.
067: */
068: public ChainingIterator(List iterators) {
069: Iterator checkIterator = iterators.iterator();
070: OJBIterator temp;
071:
072: /**
073: * validate that all items in List are iterators and
074: * they are not empty.
075: */
076: while (checkIterator.hasNext()) {
077: temp = (OJBIterator) checkIterator.next();
078: addIterator(temp);
079: }
080: }
081:
082: /**
083: * use this method to construct the ChainingIterator
084: * iterator by iterator.
085: */
086: public void addIterator(OJBIterator iterator) {
087: /**
088: * only add iterators that are not null and non-empty.
089: */
090: if (iterator != null) {
091: if (iterator.hasNext()) {
092: setNextIterator();
093: m_rsIterators.add(iterator);
094: }
095: }
096: }
097:
098: /**
099: * Calculates the size of all the iterators. Caches it for fast
100: * lookups in the future. iterators shouldn't change size after the
101: * queries have been executed so caching is safe (assumption, should check).
102: * @return the combined size of all the iterators for all extents.
103: */
104: public int size() throws PersistenceBrokerException {
105: if (m_fullSize == -1) {
106: int size = 0;
107: Iterator it = m_rsIterators.iterator();
108: while (it.hasNext()) {
109: size += ((OJBIterator) it.next()).size();
110: }
111: m_fullSize = size;
112: }
113: return m_fullSize;
114: }
115:
116: /* (non-Javadoc)
117: * @see org.apache.ojb.broker.accesslayer.OJBIterator#fullSize()
118: */
119: public int fullSize() throws PersistenceBrokerException {
120: return size();
121: }
122:
123: /**
124: * the absolute and relative calls are the trickiest parts. We have to
125: * move across cursor boundaries potentially.
126: *
127: * a + row value indexes from beginning of resultset
128: * a - row value indexes from the end of th resulset.
129: *
130: * Calling absolute(1) is the same as calling first().
131: * Calling absolute(-1) is the same as calling last().
132: */
133: public boolean absolute(int row) throws PersistenceBrokerException {
134: // 1. handle the special cases first.
135: if (row == 0) {
136: return true;
137: }
138:
139: if (row == 1) {
140: m_activeIteratorIndex = 0;
141: m_activeIterator = (OJBIterator) m_rsIterators
142: .get(m_activeIteratorIndex);
143: m_activeIterator.absolute(1);
144: return true;
145: }
146: if (row == -1) {
147: m_activeIteratorIndex = m_rsIterators.size();
148: m_activeIterator = (OJBIterator) m_rsIterators
149: .get(m_activeIteratorIndex);
150: m_activeIterator.absolute(-1);
151: return true;
152: }
153:
154: // now do the real work.
155: boolean movedToAbsolute = false;
156: boolean retval = false;
157: setNextIterator();
158:
159: // row is positive, so index from beginning.
160: if (row > 0) {
161: int sizeCount = 0;
162: Iterator it = m_rsIterators.iterator();
163: OJBIterator temp = null;
164: while (it.hasNext() && !movedToAbsolute) {
165: temp = (OJBIterator) it.next();
166: if (temp.size() < row) {
167: sizeCount += temp.size();
168: } else {
169: // move to the offset - sizecount
170: m_currentCursorPosition = row - sizeCount;
171: retval = temp.absolute(m_currentCursorPosition);
172: movedToAbsolute = true;
173: }
174: }
175:
176: }
177:
178: // row is negative, so index from end
179: else if (row < 0) {
180: int sizeCount = 0;
181: OJBIterator temp = null;
182: for (int i = m_rsIterators.size(); ((i >= 0) && !movedToAbsolute); i--) {
183: temp = (OJBIterator) m_rsIterators.get(i);
184: if (temp.size() < row) {
185: sizeCount += temp.size();
186: } else {
187: // move to the offset - sizecount
188: m_currentCursorPosition = row + sizeCount;
189: retval = temp.absolute(m_currentCursorPosition);
190: movedToAbsolute = true;
191: }
192: }
193: }
194:
195: return retval;
196: }
197:
198: /**
199: * Moves the cursor a relative number of rows.
200: * Movement can go in forward (positive) or reverse (negative).
201: *
202: * Calling relative does not "wrap" meaning if you move before first or
203: * after last you get positioned at the first or last row.
204: *
205: * Calling relative(0) does not change the cursor position.
206: *
207: * Note: Calling the method relative(1) is different from calling
208: * the method next() because is makes sense to call next() when
209: * there is no current row, for example, when the cursor is
210: * positioned before the first row or after the last row of
211: * the result set.
212: */
213: public boolean relative(int row) throws PersistenceBrokerException {
214: if (row == 0) {
215: return true;
216: }
217:
218: boolean movedToRelative = false;
219: boolean retval = false;
220: setNextIterator();
221:
222: if (row > 0) {
223: // special case checking for the iterator we're currently in
224: // (since it isn't positioned on the boundary potentially)
225: if (row > (m_activeIterator.size() - m_currentCursorPosition)) {
226: // the relative position lies over the border of the
227: // current iterator.
228:
229: // starting position counter should be set to whatever we have left in
230: // active iterator.
231: int positionCounter = m_activeIterator.size()
232: - m_currentCursorPosition;
233: for (int i = m_activeIteratorIndex + 1; ((i < m_rsIterators
234: .size()) && !movedToRelative); i++) {
235: m_activeIteratorIndex = i;
236: m_currentCursorPosition = 0;
237: m_activeIterator = (OJBIterator) m_rsIterators
238: .get(m_activeIteratorIndex);
239: if (!((row - positionCounter) > m_activeIterator
240: .size())) {
241: // the relative position requested is within this iterator.
242: m_currentCursorPosition = row - positionCounter;
243: retval = m_activeIterator
244: .relative(m_currentCursorPosition);
245: movedToRelative = true;
246: }
247: }
248: } else {
249: // the relative position lays within the current iterator.
250: retval = m_activeIterator.relative(row);
251: movedToRelative = true;
252: }
253: }
254:
255: return retval;
256: }
257:
258: /**
259: * delegate to each contained OJBIterator and release
260: * its resources.
261: */
262: public void releaseDbResources() {
263: Iterator it = m_rsIterators.iterator();
264: while (it.hasNext()) {
265: ((OJBIterator) it.next()).releaseDbResources();
266: }
267: }
268:
269: /**
270: * check the list of iterators to see if we have a next element.
271: * @return true if one of the contained iterators past the current
272: * position has a next.
273: */
274: public boolean hasNext() {
275: setNextIterator();
276: if (m_activeIterator == null) {
277: return false;
278: } else {
279: return m_activeIterator.hasNext();
280: }
281: }
282:
283: /**
284: * first checks to make sure we aren't at the end of the list of
285: * iterators, positions the cursor appropriately, then retrieves
286: * next object in active iterator.
287: * @return the next object in the iterator.
288: */
289: public Object next() {
290: setNextIterator();
291: m_currentCursorPosition++;
292: return m_activeIterator.next();
293: }
294:
295: public void remove() {
296: setNextIterator();
297: m_activeIterator.remove();
298: }
299:
300: /**
301: * Convenience routine to move to the next iterator if needed.
302: * @return true if the iterator is changed, false if no changes.
303: */
304: private boolean setNextIterator() {
305: boolean retval = false;
306: // first, check if the activeIterator is null, and set it.
307: if (m_activeIterator == null) {
308: if (m_rsIterators.size() > 0) {
309: m_activeIteratorIndex = 0;
310: m_currentCursorPosition = 0;
311: m_activeIterator = (OJBIterator) m_rsIterators
312: .get(m_activeIteratorIndex);
313: }
314: } else if (!m_activeIterator.hasNext()) {
315: if (m_rsIterators.size() > (m_activeIteratorIndex + 1)) {
316: // we still have iterators in the collection, move to the
317: // next one, increment the counter, and set the active
318: // iterator.
319: m_activeIteratorIndex++;
320: m_currentCursorPosition = 0;
321: m_activeIterator = (OJBIterator) m_rsIterators
322: .get(m_activeIteratorIndex);
323: retval = true;
324: }
325: }
326:
327: return retval;
328: }
329:
330: /**
331: * Answer true if an Iterator for a Table is already available
332: * @param aTable
333: * @return
334: */
335: public boolean containsIteratorForTable(String aTable) {
336: boolean result = false;
337:
338: if (m_rsIterators != null) {
339: for (int i = 0; i < m_rsIterators.size(); i++) {
340: OJBIterator it = (OJBIterator) m_rsIterators.get(i);
341: if (it instanceof RsIterator) {
342: if (((RsIterator) it).getClassDescriptor()
343: .getFullTableName().equals(aTable)) {
344: result = true;
345: break;
346: }
347: } else if (it instanceof ChainingIterator) {
348: result = ((ChainingIterator) it)
349: .containsIteratorForTable(aTable);
350: }
351: }
352: }
353:
354: return result;
355: }
356:
357: /**
358: * @see org.apache.ojb.broker.accesslayer.OJBIterator#disableLifeCycleEvents()
359: */
360: public void disableLifeCycleEvents() {
361: Iterator iterators = m_rsIterators.iterator();
362: while (iterators.hasNext()) {
363: OJBIterator iter = (OJBIterator) iterators.next();
364: iter.disableLifeCycleEvents();
365: }
366: }
367:
368: }
|