001/* 002 * (C) Copyright 2007-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Julien Anguenot 018 * Florent Guillaume 019 */ 020package org.nuxeo.ecm.core.search.api.client.search.results.impl; 021 022import java.util.ArrayList; 023import java.util.List; 024 025import org.nuxeo.ecm.core.api.CoreSession; 026import org.nuxeo.ecm.core.api.DocumentModel; 027import org.nuxeo.ecm.core.api.DocumentModelList; 028import org.nuxeo.ecm.core.api.DocumentSecurityException; 029import org.nuxeo.ecm.core.query.QueryParseException; 030import org.nuxeo.ecm.core.query.sql.model.SQLQuery; 031import org.nuxeo.ecm.core.search.api.client.SearchException; 032import org.nuxeo.ecm.core.search.api.client.search.results.ResultItem; 033import org.nuxeo.ecm.core.search.api.client.search.results.ResultSet; 034import org.nuxeo.runtime.api.Framework; 035 036/** 037 * Result set implementation. 038 */ 039public class ResultSetImpl extends ArrayList<ResultItem> implements ResultSet { 040 041 private static final long serialVersionUID = -6376330426798015144L; 042 043 protected final int offset; 044 045 /** 0 means all results */ 046 protected final int range; 047 048 protected final int totalHits; 049 050 protected final int pageHits; 051 052 protected final String query; 053 054 protected final SQLQuery sqlQuery; 055 056 protected final CoreSession session; 057 058 protected Boolean detachResultsFlag; 059 060 /** 061 * Constructor used when a CoreSession is available. 062 */ 063 public ResultSetImpl(String query, CoreSession session, int offset, int range, List<ResultItem> resultItems, 064 int totalHits, int pageHits) { 065 this.query = query; 066 sqlQuery = null; 067 this.session = session; 068 this.offset = offset; 069 this.range = range; 070 this.totalHits = totalHits; 071 this.pageHits = pageHits; 072 if (resultItems != null) { 073 addAll(resultItems); 074 } 075 } 076 077 public boolean detachResults() { 078 if (detachResultsFlag == null) { 079 detachResultsFlag = Framework.isBooleanPropertyTrue(ALWAYS_DETACH_SEARCH_RESULTS_KEY); 080 } 081 return detachResultsFlag.booleanValue(); 082 } 083 084 @Override 085 public int getOffset() { 086 return offset; 087 } 088 089 @Override 090 public int getRange() { 091 return range; 092 } 093 094 @Override 095 public ResultSet nextPage() throws SearchException { 096 if (!hasNextPage()) { 097 return null; 098 } 099 return replay(offset + range, range); 100 } 101 102 @Override 103 public ResultSet goToPage(int page) throws SearchException { 104 int newOffset = range * (page - 1); 105 if (newOffset >= 0 && newOffset < totalHits) { 106 return replay(newOffset, range); 107 } 108 return null; 109 } 110 111 @Override 112 public int getTotalHits() { 113 return totalHits; 114 } 115 116 @Override 117 public int getPageHits() { 118 return pageHits; 119 } 120 121 @Override 122 public boolean hasNextPage() { 123 if (range == 0) { 124 return false; 125 } 126 if (pageHits < range) { 127 return false; 128 } 129 return (offset + range) < totalHits; 130 } 131 132 @Override 133 public boolean isFirstPage() { 134 return range == 0 ? true : offset < range; 135 } 136 137 @Override 138 public ResultSet replay() throws SearchException { 139 return replay(offset, range); 140 } 141 142 @Override 143 public ResultSet replay(int offset, int range) throws SearchException { 144 if (session != null) { 145 try { 146 DocumentModelList list = session.query(query, null, range, offset, true); 147 List<ResultItem> resultItems = new ArrayList<>(list.size()); 148 for (DocumentModel doc : list) { 149 if (doc == null) { 150 continue; 151 } 152 if (detachResults()) { 153 // detach the document so that we can use it beyond the 154 // session 155 try { 156 doc.detach(true); 157 } catch (DocumentSecurityException e) { 158 // no access to the document (why?) 159 continue; 160 } 161 } 162 resultItems.add(new DocumentModelResultItem(doc)); 163 } 164 return new ResultSetImpl(query, session, offset, range, resultItems, (int) list.totalSize(), 165 list.size()); 166 } catch (QueryParseException e) { 167 throw new SearchException("QueryException for: " + query, e); 168 } 169 } 170 throw new SearchException("No session"); 171 } 172 173 @Override 174 public int getPageNumber() { 175 if (range == 0) { 176 return 1; 177 } 178 return (offset + range) / range; 179 } 180 181}