File Source: SearchResultsModel.java
/*
P/P * Method: org.apache.roller.weblogger.ui.rendering.model.SearchResultsModel__static_init
*/
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.ui.rendering.model;
20
21 import java.io.IOException;
22 import java.sql.Timestamp;
23 import java.util.Date;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.TreeMap;
27 import java.util.TreeSet;
28 import org.apache.commons.collections.comparators.ReverseComparator;
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.commons.lang.StringEscapeUtils;
31 import org.apache.lucene.document.Document;
32 import org.apache.lucene.search.Hits;
33 import org.apache.roller.weblogger.WebloggerException;
34 import org.apache.roller.weblogger.business.search.FieldConstants;
35 import org.apache.roller.weblogger.business.search.operations.SearchOperation;
36 import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
37 import org.apache.roller.weblogger.business.search.IndexManager;
38 import org.apache.roller.weblogger.business.Weblogger;
39 import org.apache.roller.weblogger.business.WebloggerFactory;
40 import org.apache.roller.weblogger.business.WeblogManager;
41 import org.apache.roller.weblogger.pojos.WeblogEntry;
42 import org.apache.roller.weblogger.pojos.WeblogEntryWrapperComparator;
43 import org.apache.roller.weblogger.pojos.wrapper.WeblogCategoryWrapper;
44 import org.apache.roller.weblogger.pojos.wrapper.WeblogEntryWrapper;
45 import org.apache.roller.weblogger.ui.rendering.pagers.SearchResultsPager;
46 import org.apache.roller.weblogger.ui.rendering.pagers.WeblogEntriesPager;
47 import org.apache.roller.weblogger.ui.rendering.util.WeblogSearchRequest;
48 import org.apache.roller.util.DateUtil;
49 import org.apache.roller.weblogger.business.URLStrategy;
50 import org.apache.roller.weblogger.util.I18nMessages;
51 import org.apache.roller.weblogger.util.Utilities;
52
53
54 /**
55 * Extends normal page renderer model to represent search results.
56 *
57 * Also adds some new methods which are specific only to search results.
58 */
/*
P/P * Method: void org.apache.roller.weblogger.ui.rendering.model.SearchResultsModel()
*
* Postconditions:
* this.categories == &new TreeSet(SearchResultsModel#3)
* this.commentForm == null
* this.errorMessage == null
* this.pageRequest == null
* this.pager == null
* this.requestParameters == null
* this.searchRequest == null
* this.urlStrategy == null
* this.weblog == null
* this.hits == 0
* ...
*/
59 public class SearchResultsModel extends PageModel {
60
61 public static final int RESULTS_PER_PAGE = 10;
62
63
64 // the original search request
65 WeblogSearchRequest searchRequest = null;
66 private URLStrategy urlStrategy = null;
67
68 // the actual search results mapped by Day -> Set of entries
69 private TreeMap results = new TreeMap(new ReverseComparator());
70
71 // the pager used by the 3.0+ rendering system
72 private SearchResultsPager pager = null;
73
74 private int hits = 0;
75 private int offset = 0;
76 private int limit = 0;
77 private Set categories = new TreeSet();
78 private boolean websiteSpecificSearch = true;
79 private String errorMessage = null;
80
81
82 public void init(Map initData) throws WebloggerException {
83
84 // we expect the init data to contain a searchRequest object
/*
P/P * Method: void init(Map)
*
* Preconditions:
* initData != null
* org/apache/roller/weblogger/util/I18nMessages.messagesMap != null
* (soft) init'ed(this.hits)
* (soft) init'ed(this.limit)
* (soft) init'ed(this.offset)
* (soft) init'ed(this.websiteSpecificSearch)
* (soft) this.results != null
*
* Presumptions:
* getMessages(...).bundle != null
* java.util.Map:get(...)@81 != null
* java.util.Map:get(...)@85 != null
* org.apache.roller.weblogger.business.Weblogger:getIndexManager(...)@106 != null
* org.apache.roller.weblogger.business.WebloggerFactory:getWeblogger(...)@106 != null
* ...
*
* Postconditions:
* this.categories == One-of{old this.categories, &new TreeSet(convertHitsToEntries#1)}
* init'ed(this.commentForm)
* possibly_updated(this.errorMessage)
* (soft) init'ed(this.hits)
* (soft) init'ed(this.limit)
* (soft) init'ed(this.offset)
* this.pageRequest != null
* this.pager in Addr_Set{&new SearchResultsPager(init#1),&new SearchResultsPager(init#3)}
* init'ed(this.requestParameters)
* (soft) this.searchRequest != null
* ...
*
* Test Vectors:
* java.util.Map:get(...)@91: Inverse{null}, Addr_Set{null}
* org.apache.commons.lang.StringUtils:isNotEmpty(...)@117: {0}, {1}
* org.apache.roller.weblogger.business.search.operations.SearchOperation:getResultsCount(...)@124: {-231..-2, 0..232-1}, {-1}
* org.apache.roller.weblogger.config.WebloggerRuntimeConfig:isSiteWideWeblog(...)@111: {0}, {1}
* org.apache.roller.weblogger.ui.rendering.util.WeblogSearchRequest:getQuery(...)@100: Inverse{null}, Addr_Set{null}
*/
85 searchRequest = (WeblogSearchRequest) initData.get("searchRequest");
86 if(searchRequest == null) {
87 throw new WebloggerException("expected searchRequest from init data");
88 }
89
90 // look for url strategy
91 urlStrategy = (URLStrategy) initData.get("urlStrategy");
92 if(urlStrategy == null) {
93 urlStrategy = WebloggerFactory.getWeblogger().getUrlStrategy();
94 }
95
96 // let parent initialize
97 super.init(initData);
98
99 // if there is no query, then we are done
100 if(searchRequest.getQuery() == null) {
101 pager = new SearchResultsPager(urlStrategy, searchRequest, results, false);
102 return;
103 }
104
105 // setup the search
106 IndexManager indexMgr = WebloggerFactory.getWeblogger().getIndexManager();
107
108 SearchOperation search = new SearchOperation(indexMgr);
109 search.setTerm(searchRequest.getQuery());
110
111 if(WebloggerRuntimeConfig.isSiteWideWeblog(searchRequest.getWeblogHandle())) {
112 this.websiteSpecificSearch = false;
113 } else {
114 search.setWebsiteHandle(searchRequest.getWeblogHandle());
115 }
116
117 if(StringUtils.isNotEmpty(searchRequest.getWeblogCategoryName())) {
118 search.setCategory(searchRequest.getWeblogCategoryName());
119 }
120
121 // execute search
122 indexMgr.executeIndexOperationNow(search);
123
124 if (search.getResultsCount() == -1) {
125 // this means there has been a parsing (or IO) error
126 this.errorMessage = I18nMessages.getMessages(searchRequest.getLocaleInstance()).getString("error.searchProblem");
127 } else {
128 Hits hits = search.getResults();
129 this.hits = search.getResultsCount();
130
131 // Convert the Hits into WeblogEntryData instances.
132 convertHitsToEntries(hits);
133 }
134
135 // search completed, setup pager based on results
136 pager = new SearchResultsPager(urlStrategy, searchRequest, results, (hits > (offset+limit)));
137 }
138
139 /**
140 * Is this page showing search results?
141 */
142 public boolean isSearchResults() {
/*
P/P * Method: bool isSearchResults()
*
* Postconditions:
* return_value == 1
*/
143 return true;
144 }
145
146 // override page model and return search results pager
147 public WeblogEntriesPager getWeblogEntriesPager() {
/*
P/P * Method: WeblogEntriesPager getWeblogEntriesPager()
*
* Preconditions:
* init'ed(this.pager)
*
* Postconditions:
* return_value == this.pager
* init'ed(return_value)
*/
148 return pager;
149 }
150
151 // override page model and return search results pager
152 public WeblogEntriesPager getWeblogEntriesPager(String category) {
/*
P/P * Method: WeblogEntriesPager getWeblogEntriesPager(String)
*
* Preconditions:
* init'ed(this.pager)
*
* Postconditions:
* return_value == this.pager
* init'ed(return_value)
*/
153 return pager;
154 }
155
156 private void convertHitsToEntries(Hits hits) throws WebloggerException {
157
158 // determine offset
/*
P/P * Method: void convertHitsToEntries(Hits)
*
* Preconditions:
* hits != null
* this.searchRequest != null
* (soft) this.results != null
* (soft) init'ed(this.websiteSpecificSearch)
*
* Presumptions:
* org.apache.lucene.document.Document:getField(...)@184 != null
* org.apache.lucene.document.Document:getField(...)@189 != null
* org.apache.lucene.document.Document:getField(...)@193 != null
* org.apache.lucene.document.Document:getField(...)@197 != null
* org.apache.lucene.document.Field:stringValue(...)@184 != null
* ...
*
* Postconditions:
* this.categories == One-of{old this.categories, &new TreeSet(convertHitsToEntries#1)}
* init'ed(this.limit)
* (soft) this.offset in -231+8..232-6
* new TreeSet(convertHitsToEntries#1) num objects == 1
* (soft) this.offset + this.limit in -231..232-1
*
* Test Vectors:
* this.websiteSpecificSearch: {0}, {1}
* java.lang.String:equals(...)@186: {0}, {1}
* java.sql.Timestamp:before(...)@205: {0}, {1}
* java.util.TreeSet:size(...)@210: {-231..0}, {1..232-1}
* org.apache.lucene.document.Document:getField(...)@196: Addr_Set{null}, Inverse{null}
*/
159 this.offset = searchRequest.getPageNum() * RESULTS_PER_PAGE;
160 if(this.offset >= hits.length()) {
161 this.offset = 0;
162 }
163
164 // determine limit
165 this.limit = RESULTS_PER_PAGE;
166 if(this.offset + this.limit > hits.length()) {
167 this.limit = hits.length() - this.offset;
168 }
169
170 try {
171 TreeSet categories = new TreeSet();
172 Weblogger roller = WebloggerFactory.getWeblogger();
173 WeblogManager weblogMgr = roller.getWeblogManager();
174
175 WeblogEntry entry = null;
176 Document doc = null;
177 String handle = null;
178 Timestamp now = new Timestamp(new Date().getTime());
179 for(int i = offset; i < offset+limit; i++) {
180
181 entry = null; // reset for each iteration
182
183 doc = hits.doc(i);
184 handle = doc.getField(FieldConstants.WEBSITE_HANDLE).stringValue();
185
186 if(websiteSpecificSearch &&
187 handle.equals(searchRequest.getWeblogHandle())) {
188
189 entry = weblogMgr.getWeblogEntry(
190 doc.getField(FieldConstants.ID).stringValue());
191 } else {
192
193 entry = weblogMgr.getWeblogEntry(
194 doc.getField(FieldConstants.ID).stringValue());
195
196 if (doc.getField(FieldConstants.CATEGORY) != null) {
197 categories.add(
198 doc.getField(FieldConstants.CATEGORY).stringValue());
199 }
200 }
201
202 // maybe null if search result returned inactive user
203 // or entry's user is not the requested user.
204 // but don't return future posts
205 if (entry != null && entry.getPubTime().before(now)) {
206 addEntryToResults(WeblogEntryWrapper.wrap(entry, urlStrategy));
207 }
208 }
209
210 if(categories.size() > 0) {
211 this.categories = categories;
212 }
213 } catch(IOException e) {
214 throw new WebloggerException(e);
215 }
216 }
217
218
219 private void addEntryToResults(WeblogEntryWrapper entry) {
220
221 // convert entry's each date to midnight (00m 00h 00s)
/*
P/P * Method: void addEntryToResults(WeblogEntryWrapper)
*
* Preconditions:
* entry != null
* entry.pojo != null
* this.results != null
*
* Test Vectors:
* java.util.TreeMap:get(...)@226: Inverse{null}, Addr_Set{null}
*/
222 Date midnight = DateUtil.getStartOfDay(entry.getPubTime());
223
224 // ensure we do not get duplicates from Lucene by
225 // using a Set Collection. Entries sorted by pubTime.
226 TreeSet set = (TreeSet) this.results.get(midnight);
227 if (set == null) {
228 // date is not mapped yet, so we need a new Set
229 set = new TreeSet( new WeblogEntryWrapperComparator());
230 this.results.put(midnight, set);
231 }
232 set.add(entry);
233 }
234
235
236 public String getTerm() {
/*
P/P * Method: String getTerm()
*
* Preconditions:
* this.searchRequest != null
*
* Postconditions:
* init'ed(return_value)
*/
237 String query = searchRequest.getQuery();
238 return (query == null) ? "" : StringEscapeUtils.escapeXml(Utilities.escapeHTML(query));
239 }
240
241 public String getRawTerm() {
/*
P/P * Method: String getRawTerm()
*
* Preconditions:
* this.searchRequest != null
*
* Postconditions:
* init'ed(return_value)
*/
242 return (searchRequest.getQuery() == null) ? "" : searchRequest.getQuery();
243 }
244
245 public int getHits() {
/*
P/P * Method: int getHits()
*
* Preconditions:
* init'ed(this.hits)
*
* Postconditions:
* return_value == this.hits
* init'ed(return_value)
*/
246 return hits;
247 }
248
249 public int getOffset() {
/*
P/P * Method: int getOffset()
*
* Preconditions:
* init'ed(this.offset)
*
* Postconditions:
* return_value == this.offset
* init'ed(return_value)
*/
250 return offset;
251 }
252
253 public int getLimit() {
/*
P/P * Method: int getLimit()
*
* Preconditions:
* init'ed(this.limit)
*
* Postconditions:
* return_value == this.limit
* init'ed(return_value)
*/
254 return limit;
255 }
256
257 public TreeMap getResults() {
/*
P/P * Method: TreeMap getResults()
*
* Preconditions:
* init'ed(this.results)
*
* Postconditions:
* return_value == this.results
* init'ed(return_value)
*/
258 return results;
259 }
260
261 public Set getCategories() {
/*
P/P * Method: Set getCategories()
*
* Preconditions:
* init'ed(this.categories)
*
* Postconditions:
* return_value == this.categories
* init'ed(return_value)
*/
262 return categories;
263 }
264
265 public boolean isWebsiteSpecificSearch() {
/*
P/P * Method: bool isWebsiteSpecificSearch()
*
* Preconditions:
* init'ed(this.websiteSpecificSearch)
*
* Postconditions:
* return_value == this.websiteSpecificSearch
* init'ed(return_value)
*/
266 return websiteSpecificSearch;
267 }
268
269 public String getErrorMessage() {
/*
P/P * Method: String getErrorMessage()
*
* Preconditions:
* init'ed(this.errorMessage)
*
* Postconditions:
* return_value == this.errorMessage
* init'ed(return_value)
*/
270 return errorMessage;
271 }
272
273 public String getWeblogCategoryName() {
/*
P/P * Method: String getWeblogCategoryName()
*
* Preconditions:
* this.searchRequest != null
*
* Postconditions:
* init'ed(return_value)
*/
274 return searchRequest.getWeblogCategoryName();
275 }
276
277 public WeblogCategoryWrapper getWeblogCategory() {
/*
P/P * Method: WeblogCategoryWrapper getWeblogCategory()
*
* Preconditions:
* this.searchRequest != null
*
* Postconditions:
* return_value == One-of{&new WeblogCategoryWrapper(wrap#1), null}
* return_value in Addr_Set{null,&new WeblogCategoryWrapper(wrap#1)}
* new WeblogCategoryWrapper(wrap#1) num objects <= 1
* new WeblogCategoryWrapper(wrap#1).pojo != null
* new WeblogCategoryWrapper(wrap#1).urlStrategy == this.urlStrategy
* init'ed(new WeblogCategoryWrapper(wrap#1).urlStrategy)
*
* Test Vectors:
* org.apache.roller.weblogger.ui.rendering.util.WeblogSearchRequest:getWeblogCategory(...)@278: Addr_Set{null}, Inverse{null}
*/
278 if(searchRequest.getWeblogCategory() != null) {
279 return WeblogCategoryWrapper.wrap(searchRequest.getWeblogCategory(), urlStrategy);
280 }
281 return null;
282 }
283
284 }
SofCheck Inspector Build Version : 2.18479
| SearchResultsModel.java |
2009-Jan-02 14:25:24 |
| SearchResultsModel.class |
2009-Sep-04 03:12:44 |