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