View Javadoc

1   /*
2   Copyright (c) 2007 Health Market Science, Inc.
3   
4   This library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8   
9   This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Lesser General Public License for more details.
13  
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17  USA
18  
19  You can contact Health Market Science at info@healthmarketscience.com
20  or at the following address:
21  
22  Health Market Science
23  2700 Horizon Drive
24  Suite 200
25  King of Prussia, PA 19406
26  */
27  
28  package com.healthmarketscience.jackcess;
29  
30  import java.io.IOException;
31  import java.util.Arrays;
32  import java.util.Collection;
33  import java.util.Iterator;
34  import java.util.List;
35  
36  import org.apache.commons.lang.ObjectUtils;
37  
38  /**
39   * Builder style class for constructing a Cursor.  By default, a cursor is
40   * created at the beginning of the table, and any start/end rows are
41   * inclusive.
42   *
43   * @author James Ahlborn
44   */
45  public class CursorBuilder {
46    /** the table which the cursor will traverse */
47    private final Table _table;
48    /** optional index to use in traversal */
49    private Index _index;
50    /** optional start row for an index cursor */
51    private Object[] _startRow;
52    /** whether or not start row for an index cursor is inclusive */
53    private boolean _startRowInclusive = true;
54    /** optional end row for an index cursor */
55    private Object[] _endRow;
56    /** whether or not end row for an index cursor is inclusive */
57    private boolean _endRowInclusive = true;
58    /** whether to start at beginning or end of cursor */
59    private boolean _beforeFirst = true;
60    /** optional save point to restore to the cursor */
61    private Cursor.Savepoint _savepoint;
62  
63    public CursorBuilder(Table table) {
64      _table = table;
65    }
66  
67    /**
68     * Sets the cursor so that it will start at the beginning (unless a
69     * savepoint is given).
70     */
71    public CursorBuilder beforeFirst() {
72      _beforeFirst = true;
73      return this;
74    }
75    
76    /**
77     * Sets the cursor so that it will start at the end (unless a savepoint is
78     * given).
79     */
80    public CursorBuilder afterLast() {
81      _beforeFirst = false;
82      return this;
83    }
84  
85    /**
86     * Sets a savepoint to restore for the initial position of the cursor.
87     */
88    public CursorBuilder restoreSavepoint(Cursor.Savepoint savepoint) {
89      _savepoint = savepoint;
90      return this;
91    }
92  
93    /**
94     * Sets an index to use for the cursor.
95     */
96    public CursorBuilder setIndex(Index index) {
97      _index = index;
98      return this;
99    }
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.getColumns();
123       if(indexColumns.size() != searchColumns.size()) {
124         continue;
125       }
126       Iterator<Column> sIter = searchColumns.iterator();
127       Iterator<Index.ColumnDescriptor> iIter = indexColumns.iterator();
128       boolean matches = true;
129       while(sIter.hasNext()) {
130         Column sCol = sIter.next();
131         Index.ColumnDescriptor iCol = iIter.next();
132         if(!ObjectUtils.equals(sCol.getName(), iCol.getName())) {
133           matches = false;
134           break;
135         }
136       }
137 
138       if(matches) {
139         _index = index;
140         found = true;
141         break;
142       }
143     }
144     if(!found) {
145       throw new IllegalArgumentException("Index with columns " +
146                                          searchColumns +
147                                          " does not exist in table " + _table);
148     }
149     return this;
150   }
151 
152   /**
153    * Sets the starting and ending row for a range based index cursor.
154    * <p>
155    * A valid index must be specified before calling this method.
156    */
157   public CursorBuilder setSpecificRow(Object[] specificRow) {
158     setStartRow(specificRow);
159     setEndRow(specificRow);
160     return this;
161   }
162   
163   /**
164    * Sets the starting and ending row for a range based index cursor to the
165    * given entry (where the given values correspond to the index's columns).
166    * <p>
167    * A valid index must be specified before calling this method.
168    */
169   public CursorBuilder setSpecificEntry(Object... specificEntry) {
170     if(specificEntry != null) {
171       setSpecificRow(_index.constructIndexRowFromEntry(specificEntry));
172     }
173     return this;
174   }
175 
176   
177   /**
178    * Sets the starting row for a range based index cursor.
179    * <p>
180    * A valid index must be specified before calling this method.
181    */
182   public CursorBuilder setStartRow(Object[] startRow) {
183     _startRow = startRow;
184     return this;
185   }
186   
187   /**
188    * Sets the starting row for a range based index cursor to the given entry
189    * (where the given values correspond to the index's columns).
190    * <p>
191    * A valid index must be specified before calling this method.
192    */
193   public CursorBuilder setStartEntry(Object... startEntry) {
194     if(startEntry != null) {
195       setStartRow(_index.constructIndexRowFromEntry(startEntry));
196     }
197     return this;
198   }
199 
200   /**
201    * Sets whether the starting row for a range based index cursor is inclusive
202    * or exclusive.
203    */
204   public CursorBuilder setStartRowInclusive(boolean inclusive) {
205     _startRowInclusive = inclusive;
206     return this;
207   }
208 
209   /**
210    * Sets the ending row for a range based index cursor.
211    * <p>
212    * A valid index must be specified before calling this method.
213    */
214   public CursorBuilder setEndRow(Object[] endRow) {
215     _endRow = endRow;
216     return this;
217   }
218   
219   /**
220    * Sets the ending row for a range based index cursor to the given entry
221    * (where the given values correspond to the index's columns).
222    * <p>
223    * A valid index must be specified before calling this method.
224    */
225   public CursorBuilder setEndEntry(Object... endEntry) {
226     if(endEntry != null) {
227       setEndRow(_index.constructIndexRowFromEntry(endEntry));
228     }
229     return this;
230   }
231 
232   /**
233    * Sets whether the ending row for a range based index cursor is inclusive
234    * or exclusive.
235    */
236   public CursorBuilder setEndRowInclusive(boolean inclusive) {
237     _endRowInclusive = inclusive;
238     return this;
239   }
240 
241   /**
242    * Returns a new cursor for the table, constructed to the given
243    * specifications.
244    */
245   public Cursor toCursor()
246     throws IOException
247   {
248     Cursor cursor = null;
249     if(_index == null) {
250       cursor = Cursor.createCursor(_table);
251     } else {
252       cursor = Cursor.createIndexCursor(_table, _index,
253                                         _startRow, _startRowInclusive,
254                                         _endRow, _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 }