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.beans;
034:
035: import com.flexive.faces.FxJsfUtils;
036: import com.flexive.faces.messages.FxFacesMsgErr;
037: import com.flexive.faces.messages.FxFacesMsgInfo;
038: import com.flexive.faces.model.FxGridDataModel;
039: import com.flexive.faces.model.FxResultSetDataModel;
040: import com.flexive.shared.CacheAdmin;
041: import com.flexive.shared.EJBLookup;
042: import com.flexive.shared.exceptions.FxApplicationException;
043: import com.flexive.shared.exceptions.FxNotFoundException;
044: import com.flexive.shared.search.*;
045: import com.flexive.shared.search.query.PropertyValueComparator;
046: import com.flexive.shared.search.query.SqlQueryBuilder;
047: import com.flexive.shared.value.BinaryDescriptor;
048: import org.apache.commons.lang.StringUtils;
049: import org.apache.commons.logging.Log;
050: import org.apache.commons.logging.LogFactory;
051: import org.apache.myfaces.component.html.ext.HtmlDataTable;
052:
053: import javax.faces.model.SelectItem;
054: import java.io.Serializable;
055: import java.util.ArrayList;
056: import java.util.List;
057:
058: public class SearchResultBean implements ActionBean, Serializable {
059: private static final long serialVersionUID = -3167186971609121457L;
060: private static final Log LOG = LogFactory
061: .getLog(SearchResultBean.class);
062:
063: private FxResultSetDataModel resultModel = null;
064: private FxGridDataModel gridModel = null;
065: private int gridRows = -1;
066: private int rowCount = -1;
067: private int gridColumns = -1;
068: private ResultLocation location = AdminResultLocations.ADMIN;
069: private HtmlDataTable resultDataTable = null;
070: private ResultSessionData sessionData = null;
071: private Briefcase briefcase = null; // cached briefcase object for briefcase queries
072:
073: // cache settings
074: private FxSQLSearchParams.CacheMode cacheMode = FxSQLSearchParams.CacheMode.ON;
075:
076: // briefcase-related fields set in the query form
077: private long briefcaseAclId;
078: private String briefcaseDescription;
079: private String briefcaseName;
080: private Boolean createBriefcase;
081:
082: /**
083: * {@inheritDoc}
084: */
085: public String getParseRequestParameters() {
086: try {
087: String action = FxJsfUtils.getParameter("action");
088: if (StringUtils.isBlank(action)) {
089: // no action requested
090: return null;
091: }
092: // hack!
093: FxJsfUtils.resetFaceletsComponent("frm");
094: if ("fulltextSearch".equals(action)) {
095: String query = FxJsfUtils.getParameter("query");
096: if (StringUtils.isBlank(query)) {
097: new FxFacesMsgErr(
098: "SearchResult.err.query.fulltext.empty")
099: .addToContext();
100: return null;
101: }
102: setQueryBuilder(new SqlQueryBuilder(location,
103: getViewType()).condition("*",
104: PropertyValueComparator.EQ, query));
105: setStartRow(0);
106: getSessionData().setBriefcaseId(-1);
107: show();
108: } else if ("nodeSearch".equals(action)) {
109: // search in subtree
110: if (StringUtils.isBlank(FxJsfUtils
111: .getParameter("nodeId"))) {
112: new FxFacesMsgErr(
113: "SearchResult.err.query.node.empty")
114: .addToContext();
115: return null;
116: }
117: setQueryBuilder(new SqlQueryBuilder(location,
118: getViewType()).isChild(FxJsfUtils
119: .getLongParameter("nodeId")));
120: setStartRow(0);
121: getSessionData().setBriefcaseId(-1);
122: show();
123: } else if ("openBriefcase".equals(action)
124: || "openBriefcaseDetails".equals(action)) {
125: if (StringUtils.isBlank(FxJsfUtils
126: .getParameter("briefcaseId"))) {
127: new FxFacesMsgErr(
128: "SearchResult.err.query.briefcase.empty")
129: .addToContext();
130: return null;
131: }
132: // TODO: open briefcase in own location
133: final long briefcaseId = FxJsfUtils
134: .getLongParameter("briefcaseId");
135: getSessionData().setBriefcaseId(briefcaseId);
136: setQueryBuilder(new SqlQueryBuilder(location,
137: getViewType()).filterBriefcase(briefcaseId));
138: setStartRow(0);
139: show();
140: }
141: } catch (Exception e) {
142: // TODO possibly pass some error message to the HTML page
143: LOG.error("Failed to parse request parameters: "
144: + e.getMessage(), e);
145: }
146: return null;
147: }
148:
149: /**
150: * Show the current search result.
151: *
152: * @return the next page
153: */
154: public String show() {
155: return "contentResult";
156: }
157:
158: /**
159: * Switch to list view.
160: *
161: * @return the next page
162: */
163: public String listView() {
164: setViewType(ResultViewType.LIST);
165: setFetchRows((Integer) getFetchRowItems().get(1).getValue());
166: setStartRow(0);
167: return show();
168: }
169:
170: /**
171: * Switch to thumbnail view.
172: *
173: * @return the next page
174: */
175: public String thumbView() {
176: setViewType(ResultViewType.THUMBNAILS);
177: setStartRow(0);
178: return show();
179: }
180:
181: public FxResultSet getResult() {
182: return resultModel != null ? resultModel.getResult() : null;
183: }
184:
185: public FxResultSetDataModel getResultModel() {
186: if (resultModel == null) {
187: refreshResults();
188: }
189: return resultModel;
190: }
191:
192: /**
193: * Like {@link #getResultModel()}, but returns all rows of the
194: * current query at once.
195: *
196: * @return a result model with all rows
197: */
198: public FxResultSetDataModel getAllRowsResultModel() {
199: if (getFetchRows() > 0) {
200: // reset result model and fetch all results
201: setFetchRows(-1);
202: resultModel = createResultModel();
203: resultModel.fetchResult(0);
204: }
205: return getResultModel();
206: }
207:
208: public FxGridDataModel getGridModel() {
209: if (gridModel == null) {
210: // calculate grid based on posted client document size (if available)
211: if (getPreviewSize().getSize() < 0) {
212: // unlimited dimensions --> show 1 thumbnail per page (original size)
213: gridRows = 1;
214: setFetchRows(-1);
215: gridColumns = 1;
216: } else {
217: calcThumbnailCount();
218: }
219: resultModel = null; // force result model refresh
220: gridModel = new FxGridDataModel(getResultModel(),
221: gridColumns);
222: }
223: return gridModel;
224: }
225:
226: public List<String> getColumnNames() {
227: if (getQueryBuilder() == null) {
228: return new ArrayList<String>(0);
229: }
230: return getQueryBuilder().getColumnNames();
231: }
232:
233: /**
234: * Returns the index of the first data column that should be visible to the user.
235: *
236: * @return the index of the first data column that should be visible to the user.
237: */
238: public int getFirstColumnIndex() {
239: final List<String> columnNames = getQueryBuilder()
240: .getColumnNames();
241: for (int i = 0; i < columnNames.size(); i++) {
242: String columnName = columnNames.get(i);
243: if (columnName.equals("*")) {
244: return i;
245: }
246: }
247: return 0;
248: }
249:
250: public SqlQueryBuilder getQueryBuilder() {
251: return getSessionData().getQueryBuilder().viewType(
252: getViewType());
253: }
254:
255: public void setQueryBuilder(SqlQueryBuilder queryBuilder) {
256: getSessionData().setQueryBuilder(queryBuilder);
257: }
258:
259: public void setStartRow(int rowStart) {
260: getSessionData().setStartRow(rowStart);
261: }
262:
263: public int getStartRow() {
264: if (resultDataTable != null) {
265: getSessionData().setStartRow(
266: getResultDataTable().getFirst());
267: }
268: return getSessionData().getStartRow();
269: }
270:
271: public int getFetchRows() {
272: return getSessionData().getFetchRows();
273: }
274:
275: public void setFetchRows(int fetchRows) {
276: getSessionData().setFetchRows(fetchRows);
277: }
278:
279: /**
280: * Returns selectitems for possible values of the fetchRows property.
281: *
282: * @return selectitems for possible values of the fetchRows property.
283: */
284: public List<SelectItem> getFetchRowItems() {
285: final List<SelectItem> result = new ArrayList<SelectItem>();
286: for (int count : new int[] { 10, 25, 50, 100 }) {
287: result
288: .add(new SelectItem(count, MessageBean
289: .getInstance().getMessage(
290: "SearchResult.label.fetchRows",
291: count)));
292: }
293: return result;
294: }
295:
296: public ResultViewType getViewType() {
297: return getSessionData().getViewType();
298: }
299:
300: public void setViewType(ResultViewType viewType) {
301: getSessionData().setViewType(viewType);
302: }
303:
304: public boolean isListView() {
305: return ResultViewType.LIST.equals(getViewType());
306: }
307:
308: public boolean isThumbnailView() {
309: return ResultViewType.THUMBNAILS.equals(getViewType());
310: }
311:
312: public void setTypeId(long typeId) {
313: getSessionData().setTypeId(typeId);
314: }
315:
316: public long getTypeId() {
317: return getSessionData().getTypeId();
318: }
319:
320: public List<FxFoundType> getContentTypes() {
321: if (resultModel != null) {
322: getSessionData().setContentTypes(
323: resultModel.getContentTypes());
324: }
325: return getSessionData().getContentTypes();
326: }
327:
328: /**
329: * Return JSF selectitems to be displayed in the UI for selecting a type of the result set.
330: *
331: * @return JSF selectitems to be displayed in the UI for selecting a type of the result set.
332: */
333: public List<SelectItem> getContentTypeItems() {
334: final List<SelectItem> items = new ArrayList<SelectItem>(
335: getContentTypes().size() + 1);
336: // "all results" item
337: items.add(new SelectItem(-1, MessageBean.getInstance()
338: .getMessage("SearchResult.label.type.all")));
339: // add an entry for every found content type
340: for (FxFoundType type : getContentTypes()) {
341: final String label = type.getDisplayName() + " ("
342: + type.getFoundEntries() + ")";
343: items.add(new SelectItem(type.getContentTypeId(), label));
344: }
345: return items;
346: }
347:
348: private void refreshResults() {
349: try {
350: resultModel = createResultModel();
351: if (getRowCount() >= 0) {
352: // use cached row count to avoid DB updates
353: resultModel.setRowCount(getRowCount());
354: } else {
355: // search not submitted yet - we'll use row 0 anyway, so submit search right now and keep row count
356: resultModel.setRowIndex(0);
357: setRowCount(resultModel.getRowCount());
358: }
359: } catch (Exception e) {
360: new FxFacesMsgErr("SearchResult.err.query", e.getMessage())
361: .addToContext();
362: }
363: }
364:
365: private FxResultSetDataModel createResultModel() {
366: if (ResultViewType.THUMBNAILS.equals(getViewType())) {
367: // determine number of row based on viewport size
368: calcThumbnailCount();
369: }
370: final FxResultSetDataModel model = new FxResultSetDataModel(
371: EJBLookup.getSearchEngine(), getQueryBuilder(),
372: getStartRow() * Math.max(1, gridColumns),
373: getFetchRows() != -1 ? getFetchRows() : 999999);
374: model.setGridColumns(gridColumns);
375: if (Boolean.TRUE.equals(createBriefcase)) {
376: if (StringUtils.isBlank(briefcaseName)) {
377: new FxFacesMsgErr("Briefcase.err.name").addToContext();
378: } else {
379: model.setBriefcaseName(briefcaseName);
380: model.setBriefcaseDescription(briefcaseDescription);
381: model
382: .setBriefcaseAcl(briefcaseAclId != -1 ? CacheAdmin
383: .getEnvironment()
384: .getACL(briefcaseAclId)
385: : null);
386: new FxFacesMsgInfo("Briefcase.nfo.created",
387: briefcaseName).addToContext();
388: }
389: }
390: model.setCacheMode(cacheMode);
391: return model;
392: }
393:
394: private void calcThumbnailCount() {
395: gridColumns = getClientSizeX() > 0 ? (getClientSizeX() - 50)
396: / Math.max(1, getPreviewSize().getSize() + 10) : 5;
397: setFetchRows(getGridRows() * gridColumns);
398: }
399:
400: public BinaryDescriptor.PreviewSizes getPreviewSize() {
401: return getSessionData().getPreviewSize();
402: }
403:
404: public void setPreviewSize(BinaryDescriptor.PreviewSizes previewSize) {
405: if (!getPreviewSize().equals(previewSize)) {
406: resetGridModel();
407: }
408: getSessionData().setPreviewSize(previewSize);
409: }
410:
411: public int getClientSizeX() {
412: return getSessionData().getClientSizeX();
413: }
414:
415: public void setClientSizeX(int clientSizeX) {
416: if (clientSizeX != getClientSizeX()) {
417: resetGridModel();
418: }
419: getSessionData().setClientSizeX(clientSizeX);
420: }
421:
422: public int getClientSizeY() {
423: return getSessionData().getClientSizeY();
424: }
425:
426: public void setClientSizeY(int clientSizeY) {
427: if (clientSizeY != getClientSizeY()) {
428: resetGridModel();
429: }
430: getSessionData().setClientSizeY(clientSizeY);
431: }
432:
433: public int getGridRows() {
434: if (gridRows == -1) {
435: gridRows = getClientSizeY() > 0 ? (getClientSizeY() - 150)
436: / Math.max(1, getPreviewSize().getSize() + 25) : 5;
437: }
438: return gridRows;
439: }
440:
441: public void setGridRows(int gridRows) {
442: this .gridRows = gridRows;
443: }
444:
445: private void resetGridModel() {
446: gridModel = null; // refresh thumbnail results
447: gridRows = -1;
448: rowCount = -1;
449: if (resultDataTable != null) {
450: // reset first row
451: resultDataTable.setFirst(0);
452: }
453: }
454:
455: public HtmlDataTable getResultDataTable() {
456: if (resultDataTable == null) {
457: resultDataTable = new HtmlDataTable();
458: }
459: return resultDataTable;
460: }
461:
462: public void setResultDataTable(HtmlDataTable resultDataTable) {
463: this .resultDataTable = resultDataTable;
464: }
465:
466: public int getRowCount() {
467: return rowCount;
468: }
469:
470: public void setRowCount(int rowCount) {
471: this .rowCount = rowCount;
472: }
473:
474: public ResultLocation getLocation() {
475: return location;
476: }
477:
478: public void setLocation(ResultLocation location) {
479: this .location = location;
480: }
481:
482: public ResultSessionData getSessionData() {
483: if (sessionData == null) {
484: sessionData = ResultSessionData.getSessionData(FxJsfUtils
485: .getSession(), location);
486: }
487: return sessionData;
488: }
489:
490: public long getBriefcaseAclId() {
491: return briefcaseAclId;
492: }
493:
494: public void setBriefcaseAclId(long briefcaseAclId) {
495: this .briefcaseAclId = briefcaseAclId;
496: }
497:
498: public String getBriefcaseDescription() {
499: return briefcaseDescription;
500: }
501:
502: public void setBriefcaseDescription(String briefcaseDescription) {
503: this .briefcaseDescription = briefcaseDescription;
504: }
505:
506: public String getBriefcaseName() {
507: return briefcaseName;
508: }
509:
510: public void setBriefcaseName(String briefcaseName) {
511: this .briefcaseName = briefcaseName;
512: }
513:
514: public Boolean getCreateBriefcase() {
515: return createBriefcase;
516: }
517:
518: public void setCreateBriefcase(Boolean createBriefcase) {
519: this .createBriefcase = createBriefcase;
520: }
521:
522: public FxSQLSearchParams.CacheMode getCacheMode() {
523: return cacheMode;
524: }
525:
526: public void setCacheMode(FxSQLSearchParams.CacheMode cacheMode) {
527: this .cacheMode = cacheMode;
528: }
529:
530: public Briefcase getBriefcase() throws FxApplicationException {
531: final long briefcaseId = getSessionData().getBriefcaseId();
532: if (briefcaseId == -1) {
533: return null;
534: }
535: if (briefcase == null || briefcase.getId() != briefcaseId) {
536: try {
537: briefcase = EJBLookup.getBriefcaseEngine().load(
538: briefcaseId);
539: } catch (FxNotFoundException e) {
540: getSessionData().setBriefcaseId(-1);
541: }
542: }
543: return briefcase;
544: }
545:
546: public long getBriefcaseId() throws FxApplicationException {
547: return getSessionData().getBriefcaseId();
548: }
549: }
|