1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.services.wcm.search.base;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import javax.jcr.Node;
27 import javax.jcr.NodeIterator;
28 import javax.jcr.Session;
29 import javax.jcr.query.Query;
30 import javax.jcr.query.QueryManager;
31 import javax.jcr.query.QueryResult;
32 import javax.jcr.query.Row;
33 import javax.jcr.query.RowIterator;
34
35 import org.exoplatform.services.jcr.ext.common.SessionProvider;
36 import org.exoplatform.services.jcr.impl.core.query.QueryImpl;
37 import org.exoplatform.services.log.ExoLogger;
38 import org.exoplatform.services.log.Log;
39 import org.exoplatform.services.security.ConversationState;
40 import org.exoplatform.services.wcm.search.SiteSearchService;
41 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
42
43
44
45
46
47
48
49 @SuppressWarnings("unchecked")
50 public class QueryResultPageList<E> extends AbstractPageList<E> {
51
52 private static final Log LOG = ExoLogger.getLogger(QueryResultPageList.class.getName());
53
54 private static final String ORDER_BY = "ORDER BY";
55
56
57 private QueryData queryData_;
58
59 private int bufferSize_;
60
61
62 protected List<E> buffer;
63
64 private Map<E, Integer> dataSet;
65
66 public QueryResultPageList(int pageSize, QueryData queryData, int total, int bufferSize,
67 NodeSearchFilter filter, SearchDataCreator creator) {
68 super(pageSize);
69 queryData_ = queryData.clone();
70 offset_ = (int)queryData.getOffset();
71 bufferSize_ = bufferSize;
72 this.filter = filter;
73 this.searchDataCreator = creator;
74 this.setAvailablePage(total);
75 removeRedundantPages(Math.min(bufferSize_ / pageSize, 5));
76 dataSet = new HashMap<E, Integer>();
77 loadedAllData_ = false;
78 }
79
80 public int getBufferSize() { return bufferSize_; }
81 public void setBufferSize(int bufferSize) { bufferSize_ = bufferSize; }
82
83 public int getOffset() { return offset_; }
84 public void setOffset(int offset) { offset_ = offset; }
85
86 public QueryData getQueryData() { return queryData_; }
87 public void setQueryData(QueryData queryData) { this.queryData_ = queryData; }
88
89
90
91
92
93
94 public void setPageSize(int pageSize)
95 {
96 super.setPageSize(pageSize);
97 offset_ = 0;
98 }
99
100 @Override
101 public List getAll() throws Exception {
102 return null;
103 }
104
105 @Override
106 protected void populateCurrentPage(int page) throws Exception {
107 if (buffer == null || buffer.size() == 0) {
108 queryDataForBuffer(page);
109 }
110 int firstBufferPage = offset_ / getPageSize() + 1;
111 int lastBufferPage = (offset_ + buffer.size() - 1) / getPageSize() + 1;
112 int bufferPage = bufferSize_ / getPageSize();
113
114 int offsetPage = firstBufferPage;
115 if (page < firstBufferPage || page > lastBufferPage || buffer.size() == 0) {
116 if (page < firstBufferPage) {
117 offsetPage = Math.max(1, page - (bufferPage / 3 * 2));
118 } else if (page > lastBufferPage) {
119 offsetPage = page;
120 }
121
122 offset_ = (offsetPage - 1) * getPageSize();
123 queryDataForBuffer(page);
124 }
125
126 currentListPage_ = new ArrayList<E>();
127 for (int i = getFrom(); i < getTo(); i++) {
128 if (i - offset_ < buffer.size()) {
129 E data = buffer.get(i - offset_);
130 currentListPage_.add(data);
131 }
132 }
133 if (currentListPage_.size() < getPageSize()) {
134 loadedAllData_ = true;
135 }
136 }
137
138 private void queryDataForBuffer(int queryPage) throws Exception {
139 buffer = new ArrayList<E>();
140 dataSet = new HashMap<E, Integer>();
141 SessionProvider sessionProvider = queryData_.isSystemSession() ? WCMCoreUtils.getSystemSessionProvider() :
142 WCMCoreUtils.getUserSessionProvider();
143 Session session = sessionProvider.getSession(queryData_.getWorkSpace(), WCMCoreUtils.getRepository());
144 QueryManager queryManager = session.getWorkspace().getQueryManager();
145 Query query = queryManager.createQuery(queryData_.getQueryStatement(), queryData_.getLanguage_());
146 int offset = offset_;
147 SiteSearchService siteSearchService = WCMCoreUtils.getService(SiteSearchService.class);
148 Map found = siteSearchService.getFoundNodes(ConversationState.getCurrent().getIdentity().getUserId(),
149 queryData_.getQueryStatement());
150 Map<Integer, Integer> drop = siteSearchService.getDropNodes(ConversationState.getCurrent().getIdentity().getUserId(),
151 queryData_.getQueryStatement());
152 for (int i = 0; i < queryPage; i++) {
153 if (drop.containsKey(i))
154 offset += drop.get(i);
155 }
156 ((QueryImpl)query).setOffset(offset);
157 long prevSize = 0;
158 int bufSize = bufferSize_;
159 while (true) {
160 int position = offset_;
161 int page = position/getPageSize() + 1;
162 int prevPage = -1;
163 drop.put(page, 0);
164 ((QueryImpl)query).setLimit(bufSize);
165 QueryResult queryResult = query.execute();
166 NodeIterator iter = queryResult.getNodes();
167 RowIterator rowIter = queryResult.getRows();
168 long size = iter.getSize();
169 int count = 0;
170 buffer.clear();
171 dataSet.clear();
172
173 while (iter.hasNext() && count < bufferSize_) {
174 Node newNode = iter.nextNode();
175 Row newRow = rowIter.nextRow();
176 if (filter != null) {
177 newNode = filter.filterNodeToDisplay(newNode);
178 }
179 if (newNode != null && searchDataCreator != null) {
180 E data = searchDataCreator.createData(newNode, newRow, null);
181 if (data != null && !dataSet.containsKey(data) && (found == null || !found.containsKey(data) || ((Integer)found.get(data)) >= page)) {
182 buffer.add(data);
183 dataSet.put(data, page);
184 count ++;
185 position++;
186 page = (position-1)/getPageSize() + 1;
187 if (page != prevPage) {
188 prevPage = page;
189 drop.put(page, 0);
190 }
191
192 if (position % getPageSize() == 0) { page++; }
193 } else { if (drop.containsKey(page)) drop.put(page, drop.get(page) + 1); }
194 } else if (newNode == null) { if (drop.containsKey(page)) drop.put(page, drop.get(page) + 1); }
195 }
196
197 if (size == prevSize) {
198 loadedAllData_ = true;
199 break;
200 }
201
202 if (count == bufferSize_) break;
203 bufSize = 2 * bufSize;
204 prevSize = size;
205 }
206 for (Map.Entry<E, Integer> e : dataSet.entrySet())
207 found.put(e.getKey(), e.getValue());
208 }
209
210 public void sortData() {
211 if (sortByField != null) {
212 String statement = queryData_.getQueryStatement().toUpperCase();
213 int orderByIndex = statement.lastIndexOf(ORDER_BY);
214 String[] orderStrings = orderByIndex >= 0 ? queryData_.getQueryStatement()
215 .substring(orderByIndex
216 + ORDER_BY.length())
217 .split(",") : new String[] {};
218
219 StringBuffer newStatement = orderByIndex >= 0 ?
220 new StringBuffer(queryData_.getQueryStatement().substring(0, orderByIndex + ORDER_BY.length())) :
221 new StringBuffer(queryData_.getQueryStatement());
222
223 newStatement.append(" ").append(getSortByField(sortByField, queryData_.getLanguage_())).
224 append(" ").append(getOrderForQuery(order, queryData_.getLanguage_()));
225 for(String orderString : orderStrings) {
226 if (!orderString.toUpperCase().contains(sortByField.toUpperCase())) {
227 newStatement.append(", ").append(orderString);
228 }
229 }
230 queryData_.setQueryStatement(newStatement.toString());
231 try {
232 buffer.clear();
233 populateCurrentPage(currentPage_);
234 } catch (Exception e) {
235 if (LOG.isWarnEnabled()) {
236 LOG.warn(e.getMessage());
237 }
238 }
239 }
240 }
241
242 private String getSortByField(String sortField, String queryLanguage) {
243 return (Query.SQL.equals(queryLanguage)? sortField : "@" + sortField) +
244 ("jcr:score".equals(sortField.toLowerCase()) ? "()" : "");
245 }
246
247 private String getOrderForQuery(String order, String queryLanguage) {
248 if (Query.SQL.equals(queryLanguage)) {
249 return order.toUpperCase().startsWith("A") ? "ASC" : "DESC";
250 } else {
251 return order.toUpperCase().startsWith("A") ? "ascending" : "descending";
252 }
253 }
254
255 @Override
256 public List<E> getPageWithOffsetCare(int page) throws Exception {
257 return getPage(offset_/getPageSize() + page);
258 }
259
260
261
262
263
264
265 @Override
266 public int getTo()
267 {
268 int to = currentPage_ * getPageSize();
269 if (to > available_ + offset_)
270 to = available_ + offset_;
271 return to;
272 }
273
274 public boolean loadedAllData() {
275 return loadedAllData_;
276 }
277
278 }