1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.web.search;
35
36 import fr.paris.lutece.portal.business.search.SearchParameterHome;
37 import fr.paris.lutece.portal.service.html.EncodingService;
38 import fr.paris.lutece.portal.service.i18n.I18nService;
39 import fr.paris.lutece.portal.service.message.SiteMessage;
40 import fr.paris.lutece.portal.service.message.SiteMessageException;
41 import fr.paris.lutece.portal.service.message.SiteMessageService;
42 import fr.paris.lutece.portal.service.plugin.Plugin;
43 import fr.paris.lutece.portal.service.search.ISponsoredLinksSearchService;
44 import fr.paris.lutece.portal.service.search.QueryEvent;
45 import fr.paris.lutece.portal.service.search.QueryListenersService;
46 import fr.paris.lutece.portal.service.search.SearchEngine;
47 import fr.paris.lutece.portal.service.search.SearchResult;
48 import fr.paris.lutece.portal.service.search.SearchService;
49 import fr.paris.lutece.portal.service.search.SponsoredLinksSearchService;
50 import fr.paris.lutece.portal.service.template.AppTemplateService;
51 import fr.paris.lutece.portal.service.util.AppLogService;
52 import fr.paris.lutece.portal.service.util.AppPropertiesService;
53 import fr.paris.lutece.portal.web.xpages.XPage;
54 import fr.paris.lutece.portal.web.xpages.XPageApplication;
55 import fr.paris.lutece.util.html.HtmlTemplate;
56 import fr.paris.lutece.util.html.Paginator;
57 import fr.paris.lutece.util.http.SecurityUtil;
58 import fr.paris.lutece.util.url.UrlItem;
59
60 import org.apache.commons.lang3.StringUtils;
61
62 import java.io.UnsupportedEncodingException;
63 import java.nio.charset.StandardCharsets;
64 import java.util.HashMap;
65 import java.util.List;
66 import java.util.Locale;
67 import java.util.Map;
68 import java.util.Optional;
69
70 import javax.inject.Inject;
71 import javax.inject.Named;
72
73 import javax.servlet.http.HttpServletRequest;
74
75
76
77
78 public class SearchApp implements XPageApplication
79 {
80
81
82
83 private static final long serialVersionUID = -9101183157272256639L;
84
85
86
87 private static final String BEAN_SEARCH_ENGINE = "searchEngine";
88 private static final String TEMPLATE_RESULTS = "skin/search/search_results.html";
89 private static final String PROPERTY_SEARCH_PAGE_URL = "search.pageSearch.baseUrl";
90 private static final String PROPERTY_RESULTS_PER_PAGE = "search.nb.docs.per.page";
91 private static final String PROPERTY_PATH_LABEL = "portal.search.search_results.pathLabel";
92 private static final String PROPERTY_PAGE_TITLE = "portal.search.search_results.pageTitle";
93 private static final String MESSAGE_INVALID_SEARCH_TERMS = "portal.search.message.invalidSearchTerms";
94 private static final String MESSAGE_ENCODING_ERROR = "portal.search.message.encodingError";
95 private static final String DEFAULT_RESULTS_PER_PAGE = "10";
96 private static final String DEFAULT_PAGE_INDEX = "1";
97 private static final String PARAMETER_PAGE_INDEX = "page_index";
98 private static final String PARAMETER_NB_ITEMS_PER_PAGE = "items_per_page";
99 private static final String PARAMETER_QUERY = "query";
100 private static final String PARAMETER_TAG_FILTER = "tag_filter";
101 private static final String PARAMETER_DEFAULT_OPERATOR = "default_operator";
102 private static final String MARK_RESULTS_LIST = "results_list";
103 private static final String MARK_QUERY = "query";
104 private static final String MARK_PAGINATOR = "paginator";
105 private static final String MARK_NB_ITEMS_PER_PAGE = "nb_items_per_page";
106 private static final String MARK_ERROR = "error";
107 private static final String MARK_SPONSOREDLINKS_SET = "sponsoredlinks_set";
108 private static final String MARK_LIST_TYPE_AND_LINK = "list_type_and_link";
109 private static final String PROPERTY_ENCODE_URI = "search.encode.uri";
110 private static final String PROPERTY_ENCODE_URI_ENCODING = "search.encode.uri.encoding";
111 private static final String CONSTANT_HTTP_METHOD_GET = "GET";
112 private static final boolean DEFAULT_ENCODE_URI = false;
113 @Inject
114 @Named( BEAN_SEARCH_ENGINE )
115 private SearchEngine _engine;
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 @Override
131 public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin ) throws SiteMessageException
132 {
133 XPagetal/web/xpages/XPage.html#XPage">XPage page = new XPage( );
134 String strQuery = request.getParameter( PARAMETER_QUERY );
135 String strTagFilter = request.getParameter( PARAMETER_TAG_FILTER );
136
137 String strEncoding = AppPropertiesService.getProperty( PROPERTY_ENCODE_URI_ENCODING, StandardCharsets.ISO_8859_1.name( ) );
138
139 if ( StringUtils.equalsIgnoreCase( CONSTANT_HTTP_METHOD_GET, request.getMethod( ) )
140 && !StringUtils.equalsIgnoreCase( strEncoding, StandardCharsets.UTF_8.name( ) ) )
141 {
142 try
143 {
144 if ( StringUtils.isNotBlank( strQuery ) )
145 {
146 strQuery = new String( strQuery.getBytes( strEncoding ), StandardCharsets.UTF_8 );
147 }
148
149 if ( StringUtils.isNotBlank( strTagFilter ) )
150 {
151 strTagFilter = new String( strTagFilter.getBytes( strEncoding ), StandardCharsets.UTF_8 );
152 }
153 }
154 catch( UnsupportedEncodingException e )
155 {
156 AppLogService.error( e.getMessage( ), e );
157 }
158 }
159
160 if ( StringUtils.isNotEmpty( strTagFilter ) )
161 {
162 strQuery = strTagFilter;
163 }
164
165 boolean bEncodeUri = Boolean.parseBoolean( AppPropertiesService.getProperty( PROPERTY_ENCODE_URI, Boolean.toString( DEFAULT_ENCODE_URI ) ) );
166
167 String strSearchPageUrl = AppPropertiesService.getProperty( PROPERTY_SEARCH_PAGE_URL );
168 String strError = "";
169 Locale locale = request.getLocale( );
170
171
172 if ( ( strQuery != null ) && ( SecurityUtil.containsXssCharacters( request, strQuery ) ) )
173 {
174 strError = I18nService.getLocalizedString( MESSAGE_INVALID_SEARCH_TERMS, locale );
175 strQuery = "";
176 }
177
178 String strDefaultNbItemPerPage = AppPropertiesService.getProperty( PROPERTY_RESULTS_PER_PAGE, DEFAULT_RESULTS_PER_PAGE );
179 String strNbItemPerPage = Optional.ofNullable( request.getParameter( PARAMETER_NB_ITEMS_PER_PAGE ) ).orElse( strDefaultNbItemPerPage );
180 int nNbItemsPerPage = Integer.parseInt( strNbItemPerPage );
181
182 String strCurrentPageIndex = Optional.ofNullable( request.getParameter( PARAMETER_PAGE_INDEX ) ).orElse( DEFAULT_PAGE_INDEX );
183
184 List<SearchResult> listResults = _engine.getSearchResults( strQuery, request );
185
186
187
188
189 notifyQueryListeners( strQuery, listResults.size( ), request );
190
191 UrlItem/url/UrlItem.html#UrlItem">UrlItem url = new UrlItem( strSearchPageUrl );
192 String strQueryForPaginator = strQuery;
193
194 if ( bEncodeUri )
195 {
196 strQueryForPaginator = encodeUrl( request, strQuery );
197 }
198
199 if ( StringUtils.isNotBlank( strTagFilter ) )
200 {
201 strQuery = "";
202 }
203
204 url.addParameter( PARAMETER_QUERY, strQueryForPaginator );
205 url.addParameter( PARAMETER_NB_ITEMS_PER_PAGE, nNbItemsPerPage );
206
207 StringBuilder sbUrl = new StringBuilder( );
208 sbUrl = sbUrl.append( url.getUrl( ) );
209
210 Map<String, Object> model = new HashMap<>( );
211 if ( StringUtils.isNotBlank( request.getParameter( PARAMETER_DEFAULT_OPERATOR ) ) )
212 {
213 sbUrl = sbUrl.append( "&default_operator=" + request.getParameter( PARAMETER_DEFAULT_OPERATOR ) );
214
215 model.put( PARAMETER_DEFAULT_OPERATOR, request.getParameter( PARAMETER_DEFAULT_OPERATOR ) );
216 }
217
218 Paginator<SearchResult> paginator = new Paginator<>( listResults, nNbItemsPerPage, sbUrl.toString( ), PARAMETER_PAGE_INDEX, strCurrentPageIndex );
219
220 model.put( MARK_RESULTS_LIST, paginator.getPageItems( ) );
221 model.put( MARK_QUERY, strQuery );
222 model.put( MARK_PAGINATOR, paginator );
223 model.put( MARK_NB_ITEMS_PER_PAGE, strNbItemPerPage );
224 model.put( MARK_ERROR, strError );
225
226 ISponsoredLinksSearchService sponsoredLinksService = new SponsoredLinksSearchService( );
227
228 if ( sponsoredLinksService.isAvailable( ) )
229 {
230 model.put( MARK_SPONSOREDLINKS_SET, sponsoredLinksService.getHtmlCode( strQuery, locale ) );
231 }
232
233 model.put( MARK_LIST_TYPE_AND_LINK, SearchService.getSearchTypesAndLinks( ) );
234 model.putAll( SearchParameterHome.findAll( ) );
235
236 HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_RESULTS, locale, model );
237 page.setPathLabel( I18nService.getLocalizedString( PROPERTY_PATH_LABEL, locale ) );
238 page.setTitle( I18nService.getLocalizedString( PROPERTY_PAGE_TITLE, locale ) );
239 page.setContent( template.getHtml( ) );
240
241 return page;
242 }
243
244
245
246
247
248
249
250
251
252
253
254
255 public static String encodeUrl( HttpServletRequest request, String strSource ) throws SiteMessageException
256 {
257 String strSourceUrl = ( strSource != null ) ? strSource : StringUtils.EMPTY;
258
259 String strEncoded = EncodingService.encodeUrl( strSourceUrl, PROPERTY_ENCODE_URI_ENCODING, StandardCharsets.ISO_8859_1.name( ) );
260
261 if ( StringUtils.isBlank( strEncoded ) && StringUtils.isNotBlank( strSourceUrl ) )
262 {
263 SiteMessageService.setMessage( request, MESSAGE_ENCODING_ERROR, SiteMessage.TYPE_ERROR );
264 }
265
266 return strEncoded;
267 }
268
269
270
271
272
273
274
275
276
277
278
279 private void notifyQueryListeners( String strQuery, int nResultsCount, HttpServletRequest request )
280 {
281 QueryEventrvice/search/QueryEvent.html#QueryEvent">QueryEvent event = new QueryEvent( );
282 event.setQuery( strQuery );
283 event.setResultsCount( nResultsCount );
284 event.setRequest( request );
285 QueryListenersService.getInstance( ).notifyListeners( event );
286 }
287 }