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.lang.StringUtils;
61
62 import java.io.UnsupportedEncodingException;
63
64 import java.util.HashMap;
65 import java.util.List;
66 import java.util.Locale;
67 import java.util.Map;
68
69 import javax.inject.Inject;
70 import javax.inject.Named;
71
72 import javax.servlet.http.HttpServletRequest;
73
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 DEFAULT_URI_ENCODING = "ISO-8859-1";
112 private static final String CONSTANT_ENCODING_UTF8 = "UTF-8";
113 private static final String CONSTANT_HTTP_METHOD_GET = "GET";
114 private static final boolean DEFAULT_ENCODE_URI = false;
115 @Inject
116 @Named( BEAN_SEARCH_ENGINE )
117 private SearchEngine _engine;
118
119
120
121
122
123
124
125
126
127
128 @Override
129 public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin )
130 throws SiteMessageException
131 {
132 XPage page = new XPage( );
133 String strQuery = request.getParameter( PARAMETER_QUERY );
134 String strTagFilter = request.getParameter( PARAMETER_TAG_FILTER );
135
136 String strEncoding = AppPropertiesService.getProperty( PROPERTY_ENCODE_URI_ENCODING, DEFAULT_URI_ENCODING );
137
138 if ( StringUtils.equalsIgnoreCase( CONSTANT_HTTP_METHOD_GET, request.getMethod( ) ) &&
139 !StringUtils.equalsIgnoreCase( strEncoding, CONSTANT_ENCODING_UTF8 ) )
140 {
141 try
142 {
143 if ( StringUtils.isNotBlank( strQuery ) )
144 {
145 strQuery = new String( strQuery.getBytes( strEncoding ), CONSTANT_ENCODING_UTF8 );
146 }
147
148 if ( StringUtils.isNotBlank( strTagFilter ) )
149 {
150 strTagFilter = new String( strTagFilter.getBytes( strEncoding ), CONSTANT_ENCODING_UTF8 );
151 }
152 }
153 catch ( UnsupportedEncodingException e )
154 {
155 AppLogService.error( e.getMessage( ), e );
156 }
157 }
158
159 if ( StringUtils.isNotEmpty( strTagFilter ) )
160 {
161 strQuery = strTagFilter;
162 }
163
164 boolean bEncodeUri = Boolean.parseBoolean( AppPropertiesService.getProperty( PROPERTY_ENCODE_URI,
165 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 strNbItemPerPage = request.getParameter( PARAMETER_NB_ITEMS_PER_PAGE );
179 String strDefaultNbItemPerPage = AppPropertiesService.getProperty( PROPERTY_RESULTS_PER_PAGE,
180 DEFAULT_RESULTS_PER_PAGE );
181 strNbItemPerPage = ( strNbItemPerPage != null ) ? strNbItemPerPage : strDefaultNbItemPerPage;
182
183 int nNbItemsPerPage = Integer.parseInt( strNbItemPerPage );
184 String strCurrentPageIndex = request.getParameter( PARAMETER_PAGE_INDEX );
185 strCurrentPageIndex = ( strCurrentPageIndex != null ) ? strCurrentPageIndex : DEFAULT_PAGE_INDEX;
186
187 List<SearchResult> listResults = _engine.getSearchResults( strQuery, request );
188
189
190
191
192 notifyQueryListeners( strQuery, listResults.size( ), request );
193
194 UrlItem url = new UrlItem( strSearchPageUrl );
195 String strQueryForPaginator = strQuery;
196
197 if ( bEncodeUri )
198 {
199 strQueryForPaginator = encodeUrl( request, strQuery );
200 }
201
202 if ( StringUtils.isNotBlank( strTagFilter ) )
203 {
204 strQuery = "";
205 }
206
207 url.addParameter( PARAMETER_QUERY, strQueryForPaginator );
208 url.addParameter( PARAMETER_NB_ITEMS_PER_PAGE, nNbItemsPerPage );
209
210 StringBuilder sbUrl = new StringBuilder( );
211 sbUrl = sbUrl.append( url.getUrl( ) );
212
213 if ( StringUtils.isNotBlank( request.getParameter( PARAMETER_DEFAULT_OPERATOR ) ) )
214 {
215 sbUrl = sbUrl.append( "&default_operator=" + request.getParameter( PARAMETER_DEFAULT_OPERATOR ) );
216 }
217
218 Paginator<SearchResult> paginator = new Paginator<SearchResult>( listResults, nNbItemsPerPage,
219 sbUrl.toString( ), PARAMETER_PAGE_INDEX, strCurrentPageIndex );
220
221 Map<String, Object> model = new HashMap<String, Object>( );
222 model.put( MARK_RESULTS_LIST, paginator.getPageItems( ) );
223 model.put( MARK_QUERY, strQuery );
224 model.put( MARK_PAGINATOR, paginator );
225 model.put( MARK_NB_ITEMS_PER_PAGE, strNbItemPerPage );
226 model.put( MARK_ERROR, strError );
227
228 ISponsoredLinksSearchService sponsoredLinksService = new SponsoredLinksSearchService( );
229
230 if ( sponsoredLinksService.isAvailable( ) )
231 {
232 model.put( MARK_SPONSOREDLINKS_SET, sponsoredLinksService.getHtmlCode( strQuery, locale ) );
233 }
234
235 model.put( MARK_LIST_TYPE_AND_LINK, SearchService.getSearchTypesAndLinks( ) );
236 model.putAll( SearchParameterHome.findAll( ) );
237
238 if ( StringUtils.isNotBlank( request.getParameter( PARAMETER_DEFAULT_OPERATOR ) ) )
239 {
240
241 model.put( PARAMETER_DEFAULT_OPERATOR, request.getParameter( PARAMETER_DEFAULT_OPERATOR ) );
242 }
243
244 HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_RESULTS, locale, model );
245
246 page.setPathLabel( I18nService.getLocalizedString( PROPERTY_PATH_LABEL, locale ) );
247 page.setTitle( I18nService.getLocalizedString( PROPERTY_PAGE_TITLE, locale ) );
248 page.setContent( template.getHtml( ) );
249
250 return page;
251 }
252
253
254
255
256
257
258
259
260 public static String encodeUrl( HttpServletRequest request, String strSource )
261 throws SiteMessageException
262 {
263 String strSourceUrl = ( strSource != null ) ? strSource : StringUtils.EMPTY;
264
265 String strEncoded = EncodingService.encodeUrl( strSourceUrl, PROPERTY_ENCODE_URI_ENCODING, DEFAULT_URI_ENCODING );
266
267 if ( StringUtils.isBlank( strEncoded ) && StringUtils.isNotBlank( strSourceUrl ) )
268 {
269 SiteMessageService.setMessage( request, MESSAGE_ENCODING_ERROR, SiteMessage.TYPE_ERROR );
270 }
271
272 return strEncoded;
273 }
274
275
276
277
278
279
280
281 private void notifyQueryListeners( String strQuery, int nResultsCount, HttpServletRequest request )
282 {
283 QueryEvent event = new QueryEvent( );
284 event.setQuery( strQuery );
285 event.setResultsCount( nResultsCount );
286 event.setRequest( request );
287 QueryListenersService.getInstance( ).notifyListeners( event );
288 }
289 }