001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2007
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.faces.model;
034:
035: import com.flexive.faces.messages.FxFacesMsgErr;
036: import com.flexive.shared.exceptions.FxApplicationException;
037: import com.flexive.shared.exceptions.FxInvalidParameterException;
038: import com.flexive.shared.interfaces.SearchEngine;
039: import com.flexive.shared.search.FxEmptyResultSet;
040: import com.flexive.shared.search.FxFoundType;
041: import com.flexive.shared.search.FxResultSet;
042: import com.flexive.shared.search.FxSQLSearchParams;
043: import com.flexive.shared.search.query.SqlQueryBuilder;
044: import com.flexive.shared.security.ACL;
045: import org.apache.commons.lang.StringUtils;
046:
047: import javax.faces.model.DataModel;
048: import java.util.List;
049:
050: public class FxResultSetDataModel extends DataModel {
051: protected FxResultSet result = null;
052: private int rowIndex = -1;
053:
054: // fields for lazy-loading
055: private SqlQueryBuilder queryBuilder = null;
056: private int startRow = -1;
057: private int fetchRows = -1;
058: private SearchEngine searchEngine = null;
059: private int rowCount = -1; // externally cached number of result rows to prevent unnecessary db access
060: private int gridColumns = 1; // result rows per output (datatable) row
061:
062: private FxSQLSearchParams.CacheMode cacheMode = FxSQLSearchParams.CacheMode.ON;
063:
064: // fields for briefcase creation
065: private ACL briefcaseAcl;
066: private String briefcaseDescription;
067: private String briefcaseName;
068:
069: /**
070: * Initialize a result set model.
071: *
072: * @param result the result set
073: */
074: public FxResultSetDataModel(FxResultSet result) {
075: super ();
076: if (result == null) {
077: throw new FxInvalidParameterException("result",
078: "ex.sqlSearch.dataModel.result.empty")
079: .asRuntimeException();
080: }
081: this .result = result;
082: this .rowIndex = result.getStartIndex();
083: this .startRow = result.getStartIndex();
084: }
085:
086: /**
087: * Initialize a result set model. A query builder is used to actually return the
088: * requested rows.
089: *
090: * @param queryBuilder the query builder to be used for submitting queries
091: * @param startRow the first row to be fetched (if not accessed via UIData)
092: * @param fetchRows the default number of rows to be fetched when the first row is accessed
093: * (should match the number of rows accessed, e.g. in the UI)
094: * @param searchEngine the search engine
095: */
096: public FxResultSetDataModel(SearchEngine searchEngine,
097: SqlQueryBuilder queryBuilder, int startRow, int fetchRows) {
098: this .searchEngine = searchEngine;
099: this .queryBuilder = queryBuilder;
100: this .startRow = startRow;
101: this .fetchRows = fetchRows;
102: this .rowIndex = startRow;
103: }
104:
105: /**
106: * {@inheritDoc}
107: */
108: @Override
109: public int getRowCount() {
110: if (rowCount >= 0) {
111: // use cached value
112: return rowCount;
113: }
114: if (result == null) {
115: fetchResult(rowIndex);
116: }
117: rowCount = result.getTotalRowCount();
118: return rowCount;
119: }
120:
121: public void setRowCount(int rowCount) {
122: this .rowCount = rowCount;
123: }
124:
125: /**
126: * {@inheritDoc}
127: */
128: @Override
129: public Object getRowData() {
130: if (rowIndex == -1) {
131: return null;
132: }
133: fetchResult(rowIndex);
134: return result.getRows().get(rowIndex - result.getStartIndex());
135: }
136:
137: /**
138: * {@inheritDoc}
139: */
140: @Override
141: public int getRowIndex() {
142: return rowIndex;
143: }
144:
145: /**
146: * {@inheritDoc}
147: */
148: @Override
149: public Object getWrappedData() {
150: return result;
151: }
152:
153: /**
154: * {@inheritDoc}
155: */
156: @Override
157: public boolean isRowAvailable() {
158: // fetchResult(rowIndex);
159: return isAvailableIndex();
160: }
161:
162: private boolean isAvailableIndex() {
163: final boolean lazyAvailable = result == null && rowIndex > -1
164: && startRow >= 0 && rowIndex >= startRow
165: && rowIndex < startRow + fetchRows;
166: final boolean resultAvailable = result != null
167: && rowIndex > -1
168: && rowIndex >= result.getStartIndex()
169: && rowIndex < result.getStartIndex()
170: + result.getRows().size();
171: return lazyAvailable || resultAvailable;
172: }
173:
174: /**
175: * {@inheritDoc}
176: */
177: @Override
178: public void setRowIndex(int rowIndex) {
179: this .rowIndex = rowIndex;
180: }
181:
182: /**
183: * {@inheritDoc}
184: */
185: @Override
186: public void setWrappedData(Object data) {
187: this .result = (FxResultSet) data;
188: setRowIndex(this .result != null ? 0 : -1);
189: }
190:
191: /**
192: * Return the wrapped result set.
193: *
194: * @return the wrapped result set.
195: */
196: public FxResultSet getResult() {
197: return this .result;
198: }
199:
200: /**
201: * Return the content types present in the result set (independent of the current view).
202: *
203: * @return the content types present in the result set (independent of the current view).
204: */
205: public List<FxFoundType> getContentTypes() {
206: return getResult().getContentTypes();
207: }
208:
209: public int getStartRow() {
210: return startRow;
211: }
212:
213: public int getFetchRows() {
214: return fetchRows;
215: }
216:
217: public ACL getBriefcaseAcl() {
218: return briefcaseAcl;
219: }
220:
221: public void setBriefcaseAcl(ACL briefcaseAcl) {
222: this .briefcaseAcl = briefcaseAcl;
223: }
224:
225: public String getBriefcaseDescription() {
226: return briefcaseDescription;
227: }
228:
229: public void setBriefcaseDescription(String briefcaseDescription) {
230: this .briefcaseDescription = briefcaseDescription;
231: }
232:
233: public String getBriefcaseName() {
234: return briefcaseName;
235: }
236:
237: public void setBriefcaseName(String briefcaseName) {
238: this .briefcaseName = briefcaseName;
239: }
240:
241: public FxSQLSearchParams.CacheMode getCacheMode() {
242: return cacheMode;
243: }
244:
245: public void setCacheMode(FxSQLSearchParams.CacheMode cacheMode) {
246: this .cacheMode = cacheMode;
247: }
248:
249: public int getGridColumns() {
250: return gridColumns;
251: }
252:
253: public void setGridColumns(int gridColumns) {
254: this .gridColumns = gridColumns;
255: }
256:
257: /**
258: * Check if the current result contains the row with the given index, or
259: * submit a new search starting at index if it doesn't.
260: *
261: * @param index the row index to be accessed
262: */
263: public void fetchResult(int index) {
264: if (queryBuilder == null || rowIndex == -1
265: || (result != null && isAvailableIndex())) {
266: // use existing data for all operations
267: return;
268: }
269: // fetch rows beginning at index
270: if (searchEngine == null) {
271: throw new FxInvalidParameterException("searchEngine",
272: "ex.sqlSearch.dataModel.searchEngine.empty")
273: .asRuntimeException();
274: }
275: /*if (queryBuilder == null) {
276: throw new FxInvalidParameterException("searchEngine", "ex.sqlSearch.dataModel.queryBuilder.empty").asRuntimeException();
277: } */
278: try {
279: FxSQLSearchParams params = new FxSQLSearchParams();
280: if (StringUtils.isNotBlank(briefcaseName)) {
281: params.saveResultInBriefcase(briefcaseName,
282: briefcaseDescription, briefcaseAcl);
283: }
284: params.setCacheMode(cacheMode);
285: result = searchEngine.search(queryBuilder.getQuery(),
286: index, fetchRows, params, queryBuilder
287: .getLocation(), queryBuilder.getViewType());
288: } catch (FxApplicationException e) {
289: result = new FxEmptyResultSet();
290: // suppress exception to allow page to be rendered normally, but add a JSF error message
291: new FxFacesMsgErr(e).addToContext();
292: }
293: }
294: }
|