View Javadoc
1   /*
2    * Copyright (c) 2002-2017, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.search.solr.nutch.web;
35  
36  import fr.paris.lutece.plugins.search.solr.business.SolrSearchResult;
37  import fr.paris.lutece.plugins.search.solr.nutch.business.NutchSearchEngine;
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.QueryEvent;
44  import fr.paris.lutece.portal.service.search.QueryListenersService;
45  import fr.paris.lutece.portal.service.template.AppTemplateService;
46  import fr.paris.lutece.portal.service.util.AppLogService;
47  import fr.paris.lutece.portal.service.util.AppPropertiesService;
48  import fr.paris.lutece.portal.web.xpages.XPage;
49  import fr.paris.lutece.portal.web.xpages.XPageApplication;
50  import fr.paris.lutece.util.html.HtmlTemplate;
51  import fr.paris.lutece.util.html.Paginator;
52  import fr.paris.lutece.util.string.StringUtil;
53  import fr.paris.lutece.util.url.UrlItem;
54  
55  import java.io.UnsupportedEncodingException;
56  
57  import java.net.URLEncoder;
58  
59  import java.util.HashMap;
60  import java.util.List;
61  import java.util.Locale;
62  import java.util.Map;
63  
64  import javax.servlet.http.HttpServletRequest;
65  
66  
67  /**
68   * This class provides search results pages.
69   */
70  public class NutchSearchApp implements XPageApplication
71  {
72      ////////////////////////////////////////////////////////////////////////////
73      // Constants
74      private static final String TEMPLATE_RESULTS = "skin/search/nutch_search_results.html";
75      private static final String PROPERTY_SEARCH_PAGE_URL = "solr.nutch.pageSearch.baseUrl";
76      private static final String PROPERTY_PATH_LABEL = "portal.search.search_results.pathLabel";
77      private static final String PROPERTY_PAGE_TITLE = "portal.search.search_results.pageTitle";
78      private static final String MESSAGE_INVALID_SEARCH_TERMS = "portal.search.message.invalidSearchTerms";
79      private static final String MESSAGE_ENCODING_ERROR = "portal.search.message.encodingError";
80      private static final String PROPERTY_SOLR_RESPONSE_MAX = "solr.nutch.reponse.max";
81      private static final String DEFAULT_PAGE_INDEX = "1";
82      private static final String PARAMETER_PAGE_INDEX = "page_index";
83      private static final String PARAMETER_NB_ITEMS_PER_PAGE = "items_per_page";
84      private static final String PARAMETER_QUERY = "query";
85      private static final String MARK_RESULTS_LIST = "results_list";
86      private static final String MARK_QUERY = "query";
87      private static final String MARK_PAGINATOR = "paginator";
88      private static final String MARK_NB_ITEMS_PER_PAGE = "nb_items_per_page";
89      private static final String MARK_ERROR = "error";
90      private static final String PROPERTY_ENCODE_URI = "search.encode.uri";
91      private static final String PROPERTY_ENCODE_URI_ENCODING = "search.encode.uri.encoding";
92  
93      //    private static final String DEFAULT_URI_ENCODING = "ISO-8859-1";
94      private static final String DEFAULT_URI_ENCODING = "UTF-8";
95      private static final boolean DEFAULT_ENCODE_URI = false;
96  
97      /**
98       * Returns search results
99       *
100      * @param request The HTTP request.
101      * @param nMode The current mode.
102      * @param plugin The plugin
103      * @return The HTML code of the page.
104      * @throws SiteMessageException exception
105      */
106     public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin )
107         throws SiteMessageException
108     {
109         XPage page = new XPage(  );
110         String strQuery = request.getParameter( PARAMETER_QUERY );
111         boolean bEncodeUri = Boolean.parseBoolean( AppPropertiesService.getProperty( PROPERTY_ENCODE_URI,
112                     Boolean.toString( DEFAULT_ENCODE_URI ) ) );
113 
114         String strSearchPageUrl = AppPropertiesService.getProperty( PROPERTY_SEARCH_PAGE_URL );
115         String strError = "";
116         Locale locale = request.getLocale(  );
117 
118         // Check XSS characters
119         if ( ( strQuery != null ) && ( StringUtil.containsXssCharacters( strQuery ) ) )
120         {
121             strError = I18nService.getLocalizedString( MESSAGE_INVALID_SEARCH_TERMS, locale );
122             strQuery = "";
123         }
124 
125         String strNbItemPerPage = request.getParameter( PARAMETER_NB_ITEMS_PER_PAGE );
126 
127         if ( strNbItemPerPage == null )
128         {
129             strNbItemPerPage = PROPERTY_SOLR_RESPONSE_MAX;
130         }
131 
132         Integer nNbItemsPerPage = new Integer( strNbItemPerPage );
133 
134         String strCurrentPageIndex = request.getParameter( PARAMETER_PAGE_INDEX );
135         strCurrentPageIndex = ( strCurrentPageIndex != null ) ? strCurrentPageIndex : DEFAULT_PAGE_INDEX;
136 
137         NutchSearchEngine engine = NutchSearchEngine.getInstance(  );
138         List<SolrSearchResult> listResults = engine.getNutchSearchResults( strQuery, request, nNbItemsPerPage );
139 
140         // The page should not be added to the cache
141 
142         // Notify results infos to QueryEventListeners 
143         notifyQueryListeners( strQuery, listResults.size(  ), request );
144 
145         UrlItem url = new UrlItem( strSearchPageUrl );
146         String strQueryForPaginator = strQuery;
147 
148         if ( bEncodeUri )
149         {
150             strQueryForPaginator = encodeUrl( request, strQuery );
151         }
152 
153         url.addParameter( PARAMETER_QUERY, strQueryForPaginator );
154         url.addParameter( PARAMETER_NB_ITEMS_PER_PAGE, nNbItemsPerPage );
155 
156         Paginator paginator = new Paginator( listResults, nNbItemsPerPage, url.getUrl(  ), PARAMETER_PAGE_INDEX,
157                 strCurrentPageIndex );
158 
159         Map<String, Object> model = new HashMap<String, Object>(  );
160         model.put( MARK_RESULTS_LIST, paginator.getPageItems(  ) );
161         model.put( MARK_QUERY, strQuery );
162         model.put( MARK_PAGINATOR, paginator );
163         model.put( MARK_NB_ITEMS_PER_PAGE, nNbItemsPerPage );
164         model.put( MARK_ERROR, strError );
165 
166         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_RESULTS, locale, model );
167 
168         page.setPathLabel( I18nService.getLocalizedString( PROPERTY_PATH_LABEL, locale ) );
169         page.setTitle( I18nService.getLocalizedString( PROPERTY_PAGE_TITLE, locale ) );
170         page.setContent( template.getHtml(  ) );
171 
172         return page;
173     }
174 
175     /**
176      * Encode an url string
177      * @param request the http request
178      * @param strSource The string to encode
179      * @return The encoded string
180      * @throws SiteMessageException exception
181      */
182     public static String encodeUrl( HttpServletRequest request, String strSource )
183         throws SiteMessageException
184     {
185         String strEncoded = "";
186         String strURIEncoding = AppPropertiesService.getProperty( PROPERTY_ENCODE_URI_ENCODING, DEFAULT_URI_ENCODING );
187 
188         try
189         {
190             strEncoded = URLEncoder.encode( strSource, strURIEncoding );
191         }
192         catch ( UnsupportedEncodingException e )
193         {
194             AppLogService.error( e.getMessage(  ), e );
195             SiteMessageService.setMessage( request, MESSAGE_ENCODING_ERROR, SiteMessage.TYPE_ERROR );
196         }
197 
198         return strEncoded;
199     }
200 
201     /**
202      * Notify all query Listeners
203      * @param strQuery The query
204      * @param nResultsCount The results count
205      * @param request The request
206      */
207     private void notifyQueryListeners( String strQuery, int nResultsCount, HttpServletRequest request )
208     {
209         QueryEvent event = new QueryEvent(  );
210         event.setQuery( strQuery );
211         event.setResultsCount( nResultsCount );
212         event.setRequest( request );
213         QueryListenersService.getInstance(  ).notifyListeners( event );
214     }
215 }