1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.search;
17
18 import static org.codelibs.core.stream.StreamUtil.stream;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.Set;
27
28 import javax.annotation.Resource;
29 import javax.servlet.http.HttpSession;
30
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
33 import org.codelibs.core.lang.StringUtil;
34 import org.codelibs.fess.Constants;
35 import org.codelibs.fess.app.web.base.FessSearchAction;
36 import org.codelibs.fess.app.web.base.SearchForm;
37 import org.codelibs.fess.entity.SearchRenderData;
38 import org.codelibs.fess.entity.SearchRequestParams.SearchRequestType;
39 import org.codelibs.fess.exception.InvalidQueryException;
40 import org.codelibs.fess.exception.ResultOffsetExceededException;
41 import org.codelibs.fess.helper.RelatedContentHelper;
42 import org.codelibs.fess.helper.RelatedQueryHelper;
43 import org.codelibs.fess.util.RenderDataUtil;
44 import org.lastaflute.taglib.function.LaFunctions;
45 import org.lastaflute.web.Execute;
46 import org.lastaflute.web.response.HtmlResponse;
47 import org.lastaflute.web.response.render.RenderData;
48 import org.lastaflute.web.util.LaRequestUtil;
49
50 public class SearchAction extends FessSearchAction {
51
52
53
54
55 private static final Logger logger = LogManager.getLogger(SearchAction.class);
56
57
58
59
60
61 @Resource
62 protected RelatedContentHelper relatedContentHelper;
63
64 @Resource
65 protected RelatedQueryHelper relatedQueryHelper;
66
67
68
69
70
71
72
73
74 @Execute
75 public HtmlResponse index(final SearchForm form) {
76 return search(form);
77 }
78
79 @Execute
80 public HtmlResponse advance(final SearchForm form) {
81 if (isLoginRequired()) {
82 return redirectToLogin();
83 }
84 validate(form, messages -> {}, () -> asHtml(virtualHost(path_IndexJsp)).renderWith(data -> {
85 buildInitParams();
86 RenderDataUtil.register(data, "notification", fessConfig.getNotificationSearchTop());
87 }));
88 if (!form.hasConditionQuery()) {
89 if (StringUtil.isNotBlank(form.q)) {
90 form.as.put("q", new String[] { form.q });
91 } else {
92
93 }
94 }
95 return asHtml(virtualHost(path_AdvanceJsp)).renderWith(data -> {
96 buildInitParams();
97 RenderDataUtil.register(data, "notification", fessConfig.getNotificationAdvanceSearch());
98 });
99 }
100
101 @Execute
102 public HtmlResponse search(final SearchForm form) {
103 if (viewHelper.isUseSession()) {
104 LaRequestUtil.getOptionalRequest().ifPresent(request -> {
105 final HttpSession session = request.getSession(false);
106 if (session != null && form.num != null) {
107 session.setAttribute(Constants.RESULTS_PER_PAGE, form.num);
108 }
109 });
110 }
111 return doSearch(form);
112 }
113
114 @Execute
115 public HtmlResponse prev(final SearchForm form) {
116 return doMove(form, -1);
117 }
118
119 @Execute
120 public HtmlResponse next(final SearchForm form) {
121 return doMove(form, 1);
122 }
123
124 @Execute
125 public HtmlResponse move(final SearchForm form) {
126 return doMove(form, 0);
127 }
128
129 protected HtmlResponse doSearch(final SearchForm form) {
130 validate(form, messages -> {}, () -> asHtml(virtualHost(path_SearchJsp)));
131 if (isLoginRequired()) {
132 return redirectToLogin();
133 }
134
135 if (viewHelper.isUseSession()) {
136 final HttpSession session = request.getSession(false);
137 if (session != null) {
138 final Object resultsPerPage = session.getAttribute(Constants.RESULTS_PER_PAGE);
139 if (resultsPerPage instanceof Integer) {
140 form.num = (Integer) resultsPerPage;
141 }
142 }
143 }
144
145 if (StringUtil.isBlank(form.q) && form.fields.isEmpty() && !form.hasConditionQuery()) {
146
147 form.q = null;
148 return redirectToRoot();
149 }
150
151 try {
152 buildFormParams(form);
153 form.lang = searchHelper.getLanguages(request, form);
154 final WebRenderData renderData = new WebRenderData();
155 searchHelper.search(form, renderData, getUserBean());
156 return asHtml(virtualHost(path_SearchJsp)).renderWith(data -> {
157 if (form.hasConditionQuery()) {
158 form.q = renderData.getSearchQuery();
159 }
160 renderData.register(data);
161 RenderDataUtil.register(data, "displayQuery", getDisplayQuery(form, labelTypeHelper
162 .getLabelTypeItemList(SearchRequestType.SEARCH, request.getLocale() == null ? Locale.ROOT : request.getLocale())));
163 createPagingQuery(form);
164 final String[] relatedContents = relatedContentHelper.getRelatedContents(form.getQuery());
165 RenderDataUtil.register(data, "relatedContents", relatedContents);
166 final String[] relatedQueries = relatedQueryHelper.getRelatedQueries(form.getQuery());
167 if (relatedQueries.length > 0) {
168 RenderDataUtil.register(data, "relatedQueries", relatedQueries);
169 }
170 });
171 } catch (final InvalidQueryException e) {
172 if (logger.isDebugEnabled()) {
173 logger.debug(e.getMessage(), e);
174 }
175 saveError(e.getMessageCode());
176 return redirectToRoot();
177 } catch (final ResultOffsetExceededException e) {
178 if (logger.isDebugEnabled()) {
179 logger.debug(e.getMessage(), e);
180 }
181 saveError(messages -> {
182 messages.addErrorsResultSizeExceeded(GLOBAL);
183 });
184 return redirectToRoot();
185 }
186 }
187
188 protected HtmlResponse doMove(final SearchForm form, final int move) {
189 int start = fessConfig.getPagingSearchPageStartAsInteger();
190 if (form.pn != null) {
191 int pageNumber = form.pn;
192 if (pageNumber > 0) {
193 pageNumber = pageNumber + move;
194 if (pageNumber < 1) {
195 pageNumber = 1;
196 }
197 start = (pageNumber - 1) * form.getPageSize();
198 }
199 }
200 form.start = start;
201
202 return doSearch(form);
203 }
204
205 protected String getDisplayQuery(final SearchForm form, final List<Map<String, String>> labelTypeItems) {
206 final StringBuilder buf = new StringBuilder(100);
207 buf.append(form.q);
208 if (!form.fields.isEmpty() && form.fields.containsKey(LABEL_FIELD)) {
209 final String[] values = form.fields.get(LABEL_FIELD);
210 final List<String> labelList = new ArrayList<>();
211 if (values != null) {
212 Collections.addAll(labelList, values);
213 }
214 for (final String labelTypeValue : labelList) {
215 for (final Map<String, String> map : labelTypeItems) {
216 if (map.get(Constants.ITEM_VALUE).equals(labelTypeValue)) {
217 buf.append(' ');
218 buf.append(map.get(Constants.ITEM_LABEL));
219 break;
220 }
221 }
222 }
223 }
224 return buf.toString();
225 }
226
227 protected void createPagingQuery(final SearchForm form) {
228 final List<String> pagingQueryList = new ArrayList<>();
229 if (form.ex_q != null) {
230 stream(form.ex_q).of(stream -> stream.filter(StringUtil::isNotBlank).distinct()
231 .forEach(q -> pagingQueryList.add("ex_q=" + LaFunctions.u(q))));
232 }
233 if (StringUtil.isNotBlank(form.sort)) {
234 pagingQueryList.add("sort=" + LaFunctions.u(form.sort));
235 }
236 if (form.lang != null) {
237 final Set<String> langSet = new HashSet<>();
238 for (final String lang : form.lang) {
239 if (StringUtil.isNotBlank(lang) && lang.length() < 1000) {
240 if (Constants.ALL_LANGUAGES.equals(lang)) {
241 langSet.clear();
242 break;
243 }
244 final String normalizeLang = systemHelper.normalizeLang(lang);
245 if (normalizeLang != null) {
246 langSet.add(normalizeLang);
247 }
248 }
249 }
250 if (!langSet.isEmpty()) {
251 for (final String lang : langSet) {
252 pagingQueryList.add("&lang=" + LaFunctions.u(lang));
253 }
254 }
255 }
256 form.fields.entrySet().stream().filter(e -> e.getValue() != null).forEach(e -> {
257 final String key = LaFunctions.u(e.getKey());
258 stream(e.getValue()).of(stream -> stream.filter(StringUtil::isNotBlank)
259 .forEach(s -> pagingQueryList.add("fields." + key + "=" + LaFunctions.u(s))));
260 });
261 form.as.entrySet().stream().filter(e -> e.getValue() != null).forEach(e -> {
262 final String key = LaFunctions.u(e.getKey());
263 stream(e.getValue()).of(stream -> stream.filter(StringUtil::isNotBlank)
264 .forEach(s -> pagingQueryList.add("as." + key + "=" + LaFunctions.u(s))));
265 });
266 request.setAttribute(Constants.PAGING_QUERY_LIST, pagingQueryList);
267 }
268
269 protected static class WebRenderData extends SearchRenderData {
270
271 public void register(final RenderData data) {
272 RenderDataUtil.register(data, "queryId", queryId);
273 RenderDataUtil.register(data, "documentItems", documentItems);
274 RenderDataUtil.register(data, "facetResponse", facetResponse);
275 RenderDataUtil.register(data, "appendHighlightParams", appendHighlightParams);
276 RenderDataUtil.register(data, "execTime", execTime);
277 RenderDataUtil.register(data, "pageSize", pageSize);
278 RenderDataUtil.register(data, "currentPageNumber", currentPageNumber);
279 RenderDataUtil.register(data, "allRecordCount", allRecordCount);
280 RenderDataUtil.register(data, "allRecordCountRelation", allRecordCountRelation);
281 RenderDataUtil.register(data, "allPageCount", allPageCount);
282 RenderDataUtil.register(data, "existNextPage", existNextPage);
283 RenderDataUtil.register(data, "existPrevPage", existPrevPage);
284 RenderDataUtil.register(data, "currentStartRecordNumber", currentStartRecordNumber);
285 RenderDataUtil.register(data, "currentEndRecordNumber", currentEndRecordNumber);
286 RenderDataUtil.register(data, "pageNumberList", pageNumberList);
287 RenderDataUtil.register(data, "partialResults", partialResults);
288 RenderDataUtil.register(data, "queryTime", queryTime);
289 RenderDataUtil.register(data, "searchQuery", searchQuery);
290 RenderDataUtil.register(data, "requestedTime", requestedTime);
291 }
292 }
293 }