001: /*
002: Copyright (c) 2007 Health Market Science, Inc.
003:
004: This library is free software; you can redistribute it and/or
005: modify it under the terms of the GNU Lesser General Public
006: License as published by the Free Software Foundation; either
007: version 2.1 of the License, or (at your option) any later version.
008:
009: This library is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public
015: License along with this library; if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017: USA
018:
019: You can contact Health Market Science at info@healthmarketscience.com
020: or at the following address:
021:
022: Health Market Science
023: 2700 Horizon Drive
024: Suite 200
025: King of Prussia, PA 19406
026: */
027:
028: package com.healthmarketscience.jackcess;
029:
030: import java.io.IOException;
031: import java.util.Arrays;
032: import java.util.Collection;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: import org.apache.commons.lang.ObjectUtils;
037:
038: /**
039: * Builder style class for constructing a Cursor. By default, a cursor is
040: * created at the beginning of the table, and any start/end rows are
041: * inclusive.
042: *
043: * @author james
044: */
045: public class CursorBuilder {
046: /** the table which the cursor will traverse */
047: private final Table _table;
048: /** optional index to use in traversal */
049: private Index _index;
050: /** optional start row for an index cursor */
051: private Object[] _startRow;
052: /** whether or not start row for an index cursor is inclusive */
053: private boolean _startRowInclusive = true;
054: /** optional end row for an index cursor */
055: private Object[] _endRow;
056: /** whether or not end row for an index cursor is inclusive */
057: private boolean _endRowInclusive = true;
058: /** whether to start at beginning or end of cursor */
059: private boolean _beforeFirst = true;
060: /** optional save point to restore to the cursor */
061: private Cursor.Savepoint _savepoint;
062:
063: public CursorBuilder(Table table) {
064: _table = table;
065: }
066:
067: /**
068: * Sets the cursor so that it will start at the beginning (unless a
069: * savepoint is given).
070: */
071: public CursorBuilder beforeFirst() {
072: _beforeFirst = true;
073: return this ;
074: }
075:
076: /**
077: * Sets the cursor so that it will start at the end (unless a savepoint is
078: * given).
079: */
080: public CursorBuilder afterLast() {
081: _beforeFirst = false;
082: return this ;
083: }
084:
085: /**
086: * Sets a savepoint to restore for the initial position of the cursor.
087: */
088: public CursorBuilder restoreSavepoint(Cursor.Savepoint savepoint) {
089: _savepoint = savepoint;
090: return this ;
091: }
092:
093: /**
094: * Sets an index to use for the cursor.
095: */
096: public CursorBuilder setIndex(Index index) {
097: _index = index;
098: return this ;
099: }
100:
101: /**
102: * Sets an index to use for the cursor by searching the table for an index
103: * with the given name.
104: * @throws IllegalArgumentException if no index can be found on the table
105: * with the given name
106: */
107: public CursorBuilder setIndexByName(String indexName) {
108: return setIndex(_table.getIndex(indexName));
109: }
110:
111: /**
112: * Sets an index to use for the cursor by searching the table for an index
113: * with exactly the given columns.
114: * @throws IllegalArgumentException if no index can be found on the table
115: * with the given name
116: */
117: public CursorBuilder setIndexByColumns(Column... columns) {
118: List<Column> searchColumns = Arrays.asList(columns);
119: boolean found = false;
120: for (Index index : _table.getIndexes()) {
121:
122: Collection<Index.ColumnDescriptor> indexColumns = index
123: .getColumns();
124: if (indexColumns.size() != searchColumns.size()) {
125: continue;
126: }
127: Iterator<Column> sIter = searchColumns.iterator();
128: Iterator<Index.ColumnDescriptor> iIter = indexColumns
129: .iterator();
130: boolean matches = true;
131: while (sIter.hasNext()) {
132: Column sCol = sIter.next();
133: Index.ColumnDescriptor iCol = iIter.next();
134: if (!ObjectUtils.equals(sCol.getName(), iCol.getName())) {
135: matches = false;
136: break;
137: }
138: }
139:
140: if (matches) {
141: _index = index;
142: found = true;
143: break;
144: }
145: }
146: if (!found) {
147: throw new IllegalArgumentException("Index with columns "
148: + searchColumns + " does not exist in table "
149: + _table);
150: }
151: return this ;
152: }
153:
154: /**
155: * Sets the starting and ending row for a range based index cursor.
156: * <p>
157: * A valid index must be specified before calling this method.
158: */
159: public CursorBuilder setSpecificRow(Object[] specificRow) {
160: setStartRow(specificRow);
161: setEndRow(specificRow);
162: return this ;
163: }
164:
165: /**
166: * Sets the starting and ending row for a range based index cursor to the
167: * given entry (where the given values correspond to the index's columns).
168: * <p>
169: * A valid index must be specified before calling this method.
170: */
171: public CursorBuilder setSpecificEntry(Object... specificEntry) {
172: if (specificEntry != null) {
173: setSpecificRow(_index
174: .constructIndexRowFromEntry(specificEntry));
175: }
176: return this ;
177: }
178:
179: /**
180: * Sets the starting row for a range based index cursor.
181: * <p>
182: * A valid index must be specified before calling this method.
183: */
184: public CursorBuilder setStartRow(Object[] startRow) {
185: _startRow = startRow;
186: return this ;
187: }
188:
189: /**
190: * Sets the starting row for a range based index cursor to the given entry
191: * (where the given values correspond to the index's columns).
192: * <p>
193: * A valid index must be specified before calling this method.
194: */
195: public CursorBuilder setStartEntry(Object... startEntry) {
196: if (startEntry != null) {
197: setStartRow(_index.constructIndexRowFromEntry(startEntry));
198: }
199: return this ;
200: }
201:
202: /**
203: * Sets whether the starting row for a range based index cursor is inclusive
204: * or exclusive.
205: */
206: public CursorBuilder setStartRowInclusive(boolean inclusive) {
207: _startRowInclusive = inclusive;
208: return this ;
209: }
210:
211: /**
212: * Sets the ending row for a range based index cursor.
213: * <p>
214: * A valid index must be specified before calling this method.
215: */
216: public CursorBuilder setEndRow(Object[] endRow) {
217: _endRow = endRow;
218: return this ;
219: }
220:
221: /**
222: * Sets the ending row for a range based index cursor to the given entry
223: * (where the given values correspond to the index's columns).
224: * <p>
225: * A valid index must be specified before calling this method.
226: */
227: public CursorBuilder setEndEntry(Object... endEntry) {
228: if (endEntry != null) {
229: setEndRow(_index.constructIndexRowFromEntry(endEntry));
230: }
231: return this ;
232: }
233:
234: /**
235: * Sets whether the ending row for a range based index cursor is inclusive
236: * or exclusive.
237: */
238: public CursorBuilder setEndRowInclusive(boolean inclusive) {
239: _endRowInclusive = inclusive;
240: return this ;
241: }
242:
243: /**
244: * Returns a new cursor for the table, constructed to the given
245: * specifications.
246: */
247: public Cursor toCursor() throws IOException {
248: Cursor cursor = null;
249: if (_index == null) {
250: cursor = Cursor.createCursor(_table);
251: } else {
252: cursor = Cursor.createIndexCursor(_table, _index,
253: _startRow, _startRowInclusive, _endRow,
254: _endRowInclusive);
255: }
256: if (_savepoint == null) {
257: if (!_beforeFirst) {
258: cursor.afterLast();
259: }
260: } else {
261: cursor.restoreSavepoint(_savepoint);
262: }
263: return cursor;
264: }
265:
266: }
|