001/* 002 * (C) Copyright 2007-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 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 * Contributors: 015 * Julien Anguenot 016 * Florent Guillaume 017 */ 018package org.nuxeo.ecm.core.search.api.client.search.results.impl; 019 020import java.util.ArrayList; 021import java.util.List; 022 023import org.nuxeo.ecm.core.api.CoreSession; 024import org.nuxeo.ecm.core.api.DocumentModel; 025import org.nuxeo.ecm.core.api.DocumentModelList; 026import org.nuxeo.ecm.core.api.DocumentSecurityException; 027import org.nuxeo.ecm.core.query.QueryParseException; 028import org.nuxeo.ecm.core.query.sql.model.SQLQuery; 029import org.nuxeo.ecm.core.search.api.client.SearchException; 030import org.nuxeo.ecm.core.search.api.client.search.results.ResultItem; 031import org.nuxeo.ecm.core.search.api.client.search.results.ResultSet; 032import org.nuxeo.runtime.api.Framework; 033 034/** 035 * Result set implementation. 036 */ 037public class ResultSetImpl extends ArrayList<ResultItem> implements ResultSet { 038 039 private static final long serialVersionUID = -6376330426798015144L; 040 041 protected final int offset; 042 043 /** 0 means all results */ 044 protected final int range; 045 046 protected final int totalHits; 047 048 protected final int pageHits; 049 050 protected final String query; 051 052 protected final SQLQuery sqlQuery; 053 054 protected final CoreSession session; 055 056 protected Boolean detachResultsFlag; 057 058 /** 059 * Constructor used when a CoreSession is available. 060 */ 061 public ResultSetImpl(String query, CoreSession session, int offset, int range, List<ResultItem> resultItems, 062 int totalHits, int pageHits) { 063 this.query = query; 064 sqlQuery = null; 065 this.session = session; 066 this.offset = offset; 067 this.range = range; 068 this.totalHits = totalHits; 069 this.pageHits = pageHits; 070 if (resultItems != null) { 071 addAll(resultItems); 072 } 073 } 074 075 public boolean detachResults() { 076 if (detachResultsFlag == null) { 077 detachResultsFlag = Framework.isBooleanPropertyTrue(ALWAYS_DETACH_SEARCH_RESULTS_KEY); 078 } 079 return detachResultsFlag.booleanValue(); 080 } 081 082 @Override 083 public int getOffset() { 084 return offset; 085 } 086 087 @Override 088 public int getRange() { 089 return range; 090 } 091 092 @Override 093 public ResultSet nextPage() throws SearchException { 094 if (!hasNextPage()) { 095 return null; 096 } 097 return replay(offset + range, range); 098 } 099 100 @Override 101 public ResultSet goToPage(int page) throws SearchException { 102 int newOffset = range * (page - 1); 103 if (newOffset >= 0 && newOffset < totalHits) { 104 return replay(newOffset, range); 105 } 106 return null; 107 } 108 109 @Override 110 public int getTotalHits() { 111 return totalHits; 112 } 113 114 @Override 115 public int getPageHits() { 116 return pageHits; 117 } 118 119 @Override 120 public boolean hasNextPage() { 121 if (range == 0) { 122 return false; 123 } 124 if (pageHits < range) { 125 return false; 126 } 127 return (offset + range) < totalHits; 128 } 129 130 @Override 131 public boolean isFirstPage() { 132 return range == 0 ? true : offset < range; 133 } 134 135 @Override 136 public ResultSet replay() throws SearchException { 137 return replay(offset, range); 138 } 139 140 @Override 141 public ResultSet replay(int offset, int range) throws SearchException { 142 if (session != null) { 143 try { 144 DocumentModelList list = session.query(query, null, range, offset, true); 145 List<ResultItem> resultItems = new ArrayList<ResultItem>(list.size()); 146 for (DocumentModel doc : list) { 147 if (doc == null) { 148 continue; 149 } 150 if (detachResults()) { 151 // detach the document so that we can use it beyond the 152 // session 153 try { 154 doc.detach(true); 155 } catch (DocumentSecurityException e) { 156 // no access to the document (why?) 157 continue; 158 } 159 } 160 resultItems.add(new DocumentModelResultItem(doc)); 161 } 162 return new ResultSetImpl(query, session, offset, range, resultItems, (int) list.totalSize(), 163 list.size()); 164 } catch (QueryParseException e) { 165 throw new SearchException("QueryException for: " + query, e); 166 } 167 } 168 throw new SearchException("No session"); 169 } 170 171 @Override 172 public int getPageNumber() { 173 if (range == 0) { 174 return 1; 175 } 176 return (offset + range) / range; 177 } 178 179}