001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.core.search;
034:
035: import com.flexive.shared.FxArrayUtils;
036: import com.flexive.shared.FxSharedUtils;
037: import com.flexive.shared.exceptions.FxInvalidParameterException;
038: import com.flexive.shared.search.*;
039: import com.flexive.sqlParser.FxStatement;
040: import com.flexive.sqlParser.SelectedValue;
041:
042: import java.io.Serializable;
043: import java.util.ArrayList;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.Map;
047:
048: /**
049: * FxResultSet implementation
050: *
051: * @author Gregor Schober (gregor.schober@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
052: * @version $Rev: 256 $
053: */
054: public class FxResultSetImpl implements Serializable, FxResultSet {
055: private static final long serialVersionUID = -7038323618490882790L;
056:
057: private final List<Object[]> rows;
058: private final String[] columnNames;
059: private final int parserExecutionTime;
060: private final int dbSearchTime;
061: private final int startIndex;
062: private final int maxFetchRows;
063: private final ResultLocation location;
064: private final ResultViewType viewType;
065: private final List<FxFoundType> contentTypes;
066: private final long creationTime;
067: private final long createdBriefcaseId;
068: private final long typeId;
069:
070: private int fetchTime = 0;
071: private int totalTime = 0;
072: private int totalRowCount;
073: private boolean truncated;
074: private Map<String, Integer> columnIndexMap;
075:
076: private class RowIterator implements Iterator<FxResultRow> {
077: int index = 0;
078:
079: public boolean hasNext() {
080: return index < rows.size();
081: }
082:
083: public FxResultRow next() {
084: return new FxResultRow(FxResultSetImpl.this , index++);
085: }
086:
087: public void remove() {
088: throw new UnsupportedOperationException(
089: "Removing rows not supported");
090: }
091: }
092:
093: protected FxResultSetImpl(ResultLocation location,
094: ResultViewType viewType) {
095: this .rows = new ArrayList<Object[]>(0);
096: this .columnNames = new String[0];
097: this .contentTypes = new ArrayList<FxFoundType>(0);
098: this .parserExecutionTime = 0;
099: this .dbSearchTime = 0;
100: this .totalRowCount = 0;
101: this .truncated = false;
102: this .startIndex = 0;
103: this .maxFetchRows = 0;
104: this .location = location;
105: this .viewType = viewType;
106: this .creationTime = System.currentTimeMillis();
107: this .typeId = -1;
108: this .createdBriefcaseId = -1;
109: }
110:
111: protected FxResultSetImpl(final FxStatement fx_stmt,
112: final int parserExecutionTime, int dbSearchTime,
113: int startIndex, int maxFetchRows, ResultLocation location,
114: ResultViewType viewType, List<FxFoundType> types,
115: long typeId, long createdBriefcaseId) {
116: this .parserExecutionTime = parserExecutionTime;
117: this .startIndex = startIndex;
118: this .maxFetchRows = maxFetchRows;
119: this .dbSearchTime = dbSearchTime;
120: this .location = location;
121: this .viewType = viewType;
122: this .contentTypes = types == null ? new ArrayList<FxFoundType>(
123: 0) : types;
124: this .createdBriefcaseId = createdBriefcaseId;
125: this .rows = new ArrayList<Object[]>(fx_stmt.getMaxResultRows());
126: this .columnNames = new String[fx_stmt.getSelectedValues()
127: .size()];
128: int pos = 0;
129: for (SelectedValue v : fx_stmt.getSelectedValues()) {
130: this .columnNames[pos++] = v.getAlias();
131: }
132: this .totalTime = parserExecutionTime;
133: this .creationTime = System.currentTimeMillis();
134: this .typeId = typeId;
135: }
136:
137: /**
138: * {@inheritDoc} *
139: */
140: public long getCreationTime() {
141: return creationTime;
142: }
143:
144: /**
145: * {@inheritDoc} *
146: */
147: public int getStartIndex() {
148: return startIndex;
149: }
150:
151: /**
152: * {@inheritDoc} *
153: */
154: public int getMaxFetchRows() {
155: return maxFetchRows;
156: }
157:
158: protected void setFetchTime(int fetchTime) {
159: this .fetchTime = fetchTime;
160: }
161:
162: protected void addRow(Object[] rowData) {
163: rows.add(rowData);
164: }
165:
166: protected void setTotalTime(int executeQueryTime) {
167: this .totalTime = executeQueryTime + parserExecutionTime;
168: }
169:
170: /**
171: * {@inheritDoc} *
172: */
173: public String[] getColumnNames() {
174: return FxArrayUtils.clone(this .columnNames);
175: }
176:
177: /**
178: * {@inheritDoc} *
179: */
180: public int getColumnIndex(String name) {
181: return FxSharedUtils.getColumnIndex(columnNames, name);
182: }
183:
184: /**
185: * {@inheritDoc} *
186: */
187: public Map<String, Integer> getColumnIndexMap() {
188: if (columnIndexMap == null) {
189: columnIndexMap = FxSharedUtils
190: .getMappedFunction(new FxSharedUtils.ParameterMapper<String, Integer>() {
191: private static final long serialVersionUID = 5832530872300639732L;
192:
193: public Integer get(Object key) {
194: return getColumnIndex(String.valueOf(key));
195: }
196: });
197: }
198: return columnIndexMap;
199: }
200:
201: /**
202: * {@inheritDoc} *
203: */
204: public List<Object[]> getRows() {
205: return rows == null ? new ArrayList<Object[]>(0) : rows;
206: }
207:
208: /**
209: * {@inheritDoc} *
210: */
211: public String getColumnName(int pos)
212: throws ArrayIndexOutOfBoundsException {
213: try {
214: return this .columnNames[pos - 1];
215: } catch (Exception exc) {
216: throw new ArrayIndexOutOfBoundsException("size: "
217: + columnNames.length + ";pos:" + pos);
218: }
219: }
220:
221: /**
222: * {@inheritDoc} *
223: */
224: public int getColumnCount() {
225: return this .columnNames.length;
226: }
227:
228: /**
229: * {@inheritDoc} *
230: */
231: public int getRowCount() {
232: return rows.size();
233: }
234:
235: /**
236: * {@inheritDoc} *
237: */
238: public int getTotalRowCount() {
239: // no type filter specified, return global total row count
240: if (typeId == -1) {
241: return totalRowCount;
242: }
243: // type filter specified, find total rows for the current type
244: for (FxFoundType contentType : contentTypes) {
245: if (contentType.getContentTypeId() == typeId) {
246: return contentType.getFoundEntries();
247: }
248: }
249: // type filter specified, but no content found
250: return 0;
251: }
252:
253: /**
254: * {@inheritDoc} *
255: */
256: public boolean isTruncated() {
257: return truncated;
258: }
259:
260: /**
261: * {@inheritDoc} *
262: */
263: public Object getObject(int rowIndex, int columnIndex)
264: throws ArrayIndexOutOfBoundsException {
265:
266: // Access row data
267: Object rowData[];
268: try {
269: rowData = this .rows.get(rowIndex - 1);
270: } catch (Exception exc) {
271: throw new ArrayIndexOutOfBoundsException("size: "
272: + columnNames.length + ";rowIndex:" + rowIndex);
273: }
274:
275: // Access column data
276: try {
277: return rowData[columnIndex - 1];
278: } catch (Exception exc) {
279: throw new ArrayIndexOutOfBoundsException("size: "
280: + columnNames.length + ";columnIndex:"
281: + columnIndex);
282: }
283: }
284:
285: /** {@inheritDoc} */
286: @SuppressWarnings({"unchecked"})
287: public <T> List<T> collectColumn(int columnIndex) {
288: final List<T> result = new ArrayList<T>(rows.size());
289: if (rows.size() == 0) {
290: return result;
291: }
292: checkColumnIndex(columnIndex);
293: for (Object[] row : rows) {
294: result.add((T) row[columnIndex - 1]);
295: }
296: return result;
297: }
298:
299: /**
300: * {@inheritDoc} *
301: */
302: public String getString(int rowIndex, int columnIndex)
303: throws ArrayIndexOutOfBoundsException {
304: Object value = getObject(rowIndex, columnIndex);
305: if (value instanceof String) {
306: return (String) value;
307: } else {
308: return value.toString();
309: }
310: }
311:
312: /**
313: * {@inheritDoc} *
314: */
315: public int getParserExecutionTime() {
316: return parserExecutionTime;
317: }
318:
319: /**
320: * Returns the time needed to find all matching records in the database.
321: *
322: * @return the time needed to find all matching records in the database
323: */
324: public int getDbSearchTime() {
325: return dbSearchTime;
326: }
327:
328: /**
329: * Returns the time needed to find fetch the matching records from the database.
330: *
331: * @return the time needed to find fetch the matching records from the database
332: */
333: public int getFetchTime() {
334: return fetchTime;
335: }
336:
337: /**
338: * Returns the total time spent for the search.
339: * <p/>
340: * This time includes the parse time, search time, fetch time and additional
341: * programm logic time.
342: *
343: * @return the total time spent for the search
344: */
345: public int getTotalTime() {
346: return totalTime;
347: }
348:
349: /**
350: * {@inheritDoc}
351: */
352: public ResultLocation getLocation() {
353: return location;
354: }
355:
356: /**
357: * {@inheritDoc}
358: */
359: public ResultViewType getViewType() {
360: return viewType;
361: }
362:
363: /**
364: * {@inheritDoc}
365: */
366: public List<FxFoundType> getContentTypes() {
367: return contentTypes;
368: }
369:
370: /**
371: * {@inheritDoc}
372: */
373: public Iterable<FxResultRow> getResultRows() {
374: return new Iterable<FxResultRow>() {
375: public Iterator<FxResultRow> iterator() {
376: return new RowIterator();
377: }
378: };
379: }
380:
381: /**
382: * {@inheritDoc}
383: */
384: public FxResultRow getResultRow(int index) {
385: return new FxResultRow(this , index);
386: }
387:
388: /**
389: * {@inheritDoc}
390: */
391: public long getCreatedBriefcaseId() {
392: return createdBriefcaseId;
393: }
394:
395: protected void setTruncated(boolean truncated) {
396: this .truncated = truncated;
397: }
398:
399: protected void setTotalRowCount(int totalRowCount) {
400: this .totalRowCount = totalRowCount;
401: }
402:
403: /**
404: * Checks the 1-based column index and throws a runtime exception when it is not valid in this result set.
405: *
406: * @param columnIndex the 1-based column index
407: */
408: private void checkColumnIndex(int columnIndex) {
409: if (rows.size() == 0) {
410: return;
411: }
412: if (rows.get(0).length < columnIndex || columnIndex < 1) {
413: throw new FxInvalidParameterException("columnIndex",
414: "ex.sqlSearch.column.index", columnIndex, rows
415: .get(0).length).asRuntimeException();
416: }
417: }
418:
419: }
|