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.directory.web;
35  
36  import java.util.ArrayList;
37  import java.util.Arrays;
38  import java.util.Date;
39  import java.util.HashMap;
40  import java.util.List;
41  import java.util.Locale;
42  import java.util.Map;
43  
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpSession;
46  
47  import org.apache.commons.lang.StringUtils;
48  
49  import fr.paris.lutece.plugins.directory.business.Directory;
50  import fr.paris.lutece.plugins.directory.business.DirectoryFilter;
51  import fr.paris.lutece.plugins.directory.business.DirectoryHome;
52  import fr.paris.lutece.plugins.directory.business.DirectoryXsl;
53  import fr.paris.lutece.plugins.directory.business.DirectoryXslHome;
54  import fr.paris.lutece.plugins.directory.business.EntryFilter;
55  import fr.paris.lutece.plugins.directory.business.EntryHome;
56  import fr.paris.lutece.plugins.directory.business.Field;
57  import fr.paris.lutece.plugins.directory.business.File;
58  import fr.paris.lutece.plugins.directory.business.FileHome;
59  import fr.paris.lutece.plugins.directory.business.IEntry;
60  import fr.paris.lutece.plugins.directory.business.PhysicalFile;
61  import fr.paris.lutece.plugins.directory.business.PhysicalFileHome;
62  import fr.paris.lutece.plugins.directory.business.Record;
63  import fr.paris.lutece.plugins.directory.business.RecordField;
64  import fr.paris.lutece.plugins.directory.business.RecordFieldFilter;
65  import fr.paris.lutece.plugins.directory.business.RecordFieldHome;
66  import fr.paris.lutece.plugins.directory.service.record.IRecordService;
67  import fr.paris.lutece.plugins.directory.service.record.RecordService;
68  import fr.paris.lutece.plugins.directory.utils.DirectoryErrorException;
69  import fr.paris.lutece.plugins.directory.utils.DirectoryUtils;
70  import fr.paris.lutece.plugins.directory.web.action.DirectorySiteSearchFields;
71  import fr.paris.lutece.plugins.workflowcore.business.state.State;
72  import fr.paris.lutece.portal.service.content.XPageAppService;
73  import fr.paris.lutece.portal.service.html.XmlTransformerService;
74  import fr.paris.lutece.portal.service.i18n.I18nService;
75  import fr.paris.lutece.portal.service.message.SiteMessage;
76  import fr.paris.lutece.portal.service.message.SiteMessageException;
77  import fr.paris.lutece.portal.service.message.SiteMessageService;
78  import fr.paris.lutece.portal.service.plugin.Plugin;
79  import fr.paris.lutece.portal.service.portal.PortalService;
80  import fr.paris.lutece.portal.service.search.SearchEngine;
81  import fr.paris.lutece.portal.service.search.SearchResult;
82  import fr.paris.lutece.portal.service.security.LuteceUser;
83  import fr.paris.lutece.portal.service.security.SecurityService;
84  import fr.paris.lutece.portal.service.security.UserNotSignedException;
85  import fr.paris.lutece.portal.service.spring.SpringContextService;
86  import fr.paris.lutece.portal.service.template.AppTemplateService;
87  import fr.paris.lutece.portal.service.util.AppPathService;
88  import fr.paris.lutece.portal.service.util.AppPropertiesService;
89  import fr.paris.lutece.portal.service.workflow.WorkflowService;
90  import fr.paris.lutece.portal.web.xpages.XPage;
91  import fr.paris.lutece.portal.web.xpages.XPageApplication;
92  import fr.paris.lutece.util.UniqueIDGenerator;
93  import fr.paris.lutece.util.date.DateUtil;
94  import fr.paris.lutece.util.html.HtmlTemplate;
95  import fr.paris.lutece.util.html.Paginator;
96  import fr.paris.lutece.util.http.SecurityUtil;
97  import fr.paris.lutece.util.url.UrlItem;
98  import fr.paris.lutece.util.xml.XmlUtil;
99  
100 /**
101  * This class manages DirectoryApp page.
102  */
103 public class DirectoryApp implements XPageApplication
104 {
105     /**
106      * Serial version UID
107      */
108 
109     private static final long serialVersionUID = 3679144166666894465L;
110 
111     // templates
112     private static final String TEMPLATE_XPAGE_FRAME_DIRECTORY = "skin/plugins/directory/directory_frame.html";
113     private static final String TEMPLATE_XPAGE_VIEW_ALL_DIRECTORIES = "skin/plugins/directory/view_all_directories.html";
114     private static final String TEMPLATE_XML_FORM_SEARCH = "skin/plugins/directory/xml_form_search.html";
115 
116     // properties for page titles and path label
117     private static final String PROPERTY_XPAGE_PAGETITLE = "directory.xpage.pagetitle";
118     private static final String PROPERTY_XPAGE_PATHLABEL = "directory.xpage.pathlabel";
119     private static final String PROPERTY_PAGE_APPLICATION_ID = "directory.xpage.applicationId";
120     private static final String PROPERTY_DIRECTORY_FRAME_TITLE_DESCRIPTIVE = "directory.directory_frame.title_descriptive";
121     private static final String PROPERTY_DIRECTORY_FRAME_TITLE_BACK_SEARCH = "directory.directory_frame.title_back_search";
122     private static final String PROPERTY_DIRECTORY_FRAME_LABEL_BACK_SEARCH = "directory.directory_frame.label_back_search";
123     private static final String PROPERTY_DIRECTORY_FRAME_TITLE_BACK_RECORD = "directory.directory_frame.title_back_record";
124     private static final String PROPERTY_DIRECTORY_FRAME_LABEL_BACK_RECORD = "directory.directory_frame.label_back_record";
125     private static final String PROPERTY_DIRECTORY_RESULT_TITLE_SORT_ASC = "directory.directory_result_list.tiltle_sort_asc";
126     private static final String PROPERTY_DIRECTORY_RESULT_TITLE_SORT_DESC = "directory.directory_result_list.tiltle_sort_desc";
127     private static final String PROPERTY_ENTRY_TYPE_GEOLOCATION = "directory.entry_type.geolocation";
128     private static final String PROPERTY_DISPLAY_ONE_RESULT_DIRECTLY = "directory.display_one_result_directly";
129 
130     // request parameters
131     private static final String PARAMETER_VIEW_DIRECTORY_RECORD = "view_directory_record";
132     private static final String PARAMETER_ID_DIRECTORY = "id_directory";
133     private static final String PARAMETER_SEARCH = "search";
134     private static final String PARAMETER_ID_DIRECTORY_RECORD = "id_directory_record";
135     private static final String INIT_MAP_QUERY = "init_map_query";
136     private static final String PARAMETER_DATE_BEGIN = "date_after";
137     private static final String PARAMETER_DATE_END = "date_before";
138     private static final String PARAMETER_OPERATOR = "default_operator";
139     private static final String PARAMETER_QUERY = "query";
140 
141     // message
142     private static final String MESSAGE_ERROR = "directory.message.Error";
143     private static final String MESSAGE_ACCESS_DENIED = "directory.message.accessDenied";
144     private static final String MESSAGE_INVALID_SEARCH_TERMS = "directory.message.invalidSearchTerms";
145     private static final String MESSAGE_SEARCH_DATE_VALIDITY = "directory.message.dateValidity";
146     private static final String MESSAGE_SEARCH_OPERATOR_VALIDITY = "directory.message.operatorValidity";
147 
148     // Markers
149     private static final String MARK_UNAVAILABILITY_MESSAGE = "unavailability_message";
150     private static final String MARK_ENTRY_LIST_GEOLOCATION = "entry_list_geolocation";
151     private static final String MARK_ENTRY_LIST_FORM_MAIN_SEARCH = "entry_list_form_main_search";
152     private static final String MARK_ENTRY_LIST_FORM_COMPLEMENTARY_SEARCH = "entry_list_form_complementary_search";
153     private static final String MARK_MAP_ID_ENTRY_LIST_RECORD_FIELD = "map_id_entry_list_record_field";
154     private static final String MARK_DIRECTORY = "directory";
155     private static final String MARK_STR_FORM_SEARCH = "str_form_search";
156     private static final String MARK_STR_RESULT_LIST = "str_result_list";
157     private static final String MARK_RESULT_RECORD_FIELD_LIST = "result_record_field_list";
158     private static final String MARK_WEBAPP_URL = "webapp_url";
159     private static final String MARK_STR_RESULT_RECORD = "str_result_record";
160     private static final String MARK_LOCALE = "locale";
161     private static final String MARK_PAGINATOR = "paginator";
162     private static final String MARK_DIRECTORY_LIST = "directory_list";
163     private static final String MARK_ONE_RESULT = "one_result";
164     private static final String MARK_ONE_SESSION_ID = "one_session_id";
165     private static final String MARK_NEW_SEARCH = "new_search";
166     private static final String MARK_DATE_BEGIN = "date_after";
167     private static final String MARK_DATE_END = "date_before";
168     private static final String MARK_OPERATOR = "operator";
169     private static final String MARK_QUERY = "query";
170     private static final String MARK_RESULT_LIST = "result_list";
171     private static final String MARK_IS_EXTEND_INSTALLED = "isExtendInstalled";
172 
173     // Markers XSL
174     private static final String MARK_TITLE_DESCRIPTIVE = "title-descriptive";
175     private static final String MARK_TITLE_BACK_SEARCH = "title-back-search";
176     private static final String MARK_LABEL_BACK_SEARCH = "label-back-search";
177     private static final String MARK_ID_DIRECTORY = "id-directory";
178     private static final String MARK_TITLE_BACK_RECORD = "title-back-record";
179     private static final String MARK_LABEL_BACK_RECORD = "label-back-record";
180     private static final String MARK_ID_LAST_RECORD = "id-last-record";
181     private static final String MARK_ID_LAST_DIRECTORY = "id-last-directory";
182     private static final String MARK_TITLE_SORT_ASC = "title-sort-asc";
183     private static final String MARK_TITLE_SORT_DESC = "title-sort-desc";
184 
185     // session filter
186     private static final String SESSION_ONE_RECORD_ID = "one_record_id";
187     private static final String SESSION_ID_LAST_RECORD = "id_last_record";
188     private static final String SESSION_ID_LAST_DIRECTORY = "id_last_directory";
189     private static final String SESSION_DIRECTORY_SITE_SEARCH_FIELDS = "search_fields";
190 
191     // message
192     private static final String MESSAGE_DIRECTORY_ERROR = "directory.message.directory_error";
193     private static final String MESSAGE_DIRECTORY_ERROR_MANDATORY_FIELD = "directory.message.directory_error.mandatory.field";
194 
195     // Properties
196     private static final String XSL_UNIQUE_PREFIX_ID = UniqueIDGenerator.getNewId( ) + "directory-";
197     private static final String OPERATOR_AND = "AND";
198     private static final String OPERATOR_OR = "OR";
199     private static final String BEAN_SEARCH_ENGINE = "searchEngine";
200 
201     // Tag
202     private static final String TAG_DISPLAY = "display";
203     private static final String TAG_YES = "yes";
204     private static final String TAG_NO = "no";
205     private static final String TAG_STATUS = "status";
206 
207     /**
208      * Returns the Directory XPage result content depending on the request parameters and the current mode.
209      *
210      * @param request
211      *            The HTTP request.
212      * @param nMode
213      *            The current mode.
214      * @param plugin
215      *            The Plugin.
216      * @return The page content.
217      * @throws SiteMessageException
218      *             the SiteMessageException
219      * @throws UserNotSignedException
220      *             the UserNotSignedException
221      */
222     @Override
223     public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin ) throws SiteMessageException, UserNotSignedException
224     {
225         XPage page = new XPage( );
226 
227         page.setTitle( I18nService.getLocalizedString( PROPERTY_XPAGE_PAGETITLE, request.getLocale( ) ) );
228         page.setPathLabel( I18nService.getLocalizedString( PROPERTY_XPAGE_PATHLABEL, request.getLocale( ) ) );
229 
230         Map<String, Object> model = new HashMap<String, Object>( );
231 
232         String strIdDirectory = request.getParameter( PARAMETER_ID_DIRECTORY );
233         String strIdDirectoryRecord = request.getParameter( PARAMETER_ID_DIRECTORY_RECORD );
234 
235         List<Record> listRecord = new ArrayList<Record>( );
236         List<Integer> listIdDirectory = new ArrayList<Integer>( );
237 
238         Boolean bSingleResult = null;
239 
240         if ( ( strIdDirectory == null ) && ( strIdDirectoryRecord == null ) )
241         {
242             page.setContent( getSearchPage( request, plugin ) );
243         }
244         else
245         {
246             Directory directory;
247             HttpSession session = request.getSession( );
248             int nIdDirectory = DirectoryUtils.convertStringToInt( strIdDirectory );
249             directory = DirectoryHome.findByPrimaryKey( nIdDirectory, plugin );
250 
251             DirectorySiteSearchFields searchFields = ( session.getAttribute( SESSION_DIRECTORY_SITE_SEARCH_FIELDS ) != null ) ? (DirectorySiteSearchFields) session
252                     .getAttribute( SESSION_DIRECTORY_SITE_SEARCH_FIELDS ) : getInitDirectorySearchField( );
253 
254             model.put( MARK_DIRECTORY, directory );
255 
256             IRecordService recordService = SpringContextService.getBean( RecordService.BEAN_SERVICE );
257 
258             int nIdDirectoryRecord = DirectoryUtils.convertStringToInt( strIdDirectoryRecord );
259             Record record = null;
260 
261             if ( request.getParameter( PARAMETER_VIEW_DIRECTORY_RECORD ) != null )
262             {
263                 record = recordService.findByPrimaryKey( nIdDirectoryRecord, plugin );
264 
265                 if ( ( record != null ) && ( record.getDirectory( ) != null ) )
266                 {
267                     directory = DirectoryHome.findByPrimaryKey( record.getDirectory( ).getIdDirectory( ), plugin );
268 
269                     listRecord = (List<Record>) session.getAttribute( SESSION_ID_LAST_RECORD );
270 
271                     if ( ( listRecord != null ) && ( listRecord.size( ) > 0 )
272                             && ( listRecord.get( listRecord.size( ) - 1 ).getIdRecord( ) != record.getIdRecord( ) ) )
273                     {
274                         listRecord.add( record );
275                     }
276                     else
277                         if ( listRecord == null )
278                         {
279                             listRecord = new ArrayList<Record>( );
280                             listRecord.add( record );
281                         }
282 
283                     session.setAttribute( SESSION_ID_LAST_RECORD, listRecord );
284 
285                     listIdDirectory = (List<Integer>) session.getAttribute( SESSION_ID_LAST_DIRECTORY );
286 
287                     if ( ( listIdDirectory != null ) && ( listIdDirectory.size( ) > 0 )
288                             && !listIdDirectory.get( listIdDirectory.size( ) - 1 ).equals( record.getDirectory( ).getIdDirectory( ) ) )
289                     {
290                         listIdDirectory.add( record.getDirectory( ).getIdDirectory( ) );
291                     }
292                     else
293                         if ( listIdDirectory == null )
294                         {
295                             listIdDirectory = new ArrayList<Integer>( );
296                             listIdDirectory.add( record.getDirectory( ).getIdDirectory( ) );
297                         }
298 
299                     session.setAttribute( SESSION_ID_LAST_DIRECTORY, listIdDirectory );
300                 }
301             }
302 
303             String strPortalUrl = AppPathService.getPortalUrl( );
304             UrlItem urlDirectoryXpage = new UrlItem( strPortalUrl );
305             urlDirectoryXpage.addParameter( XPageAppService.PARAM_XPAGE_APP, AppPropertiesService.getProperty( PROPERTY_PAGE_APPLICATION_ID ) );
306             urlDirectoryXpage.addParameter( PARAMETER_ID_DIRECTORY, strIdDirectory );
307 
308             if ( directory == null )
309             {
310                 SiteMessageService.setMessage( request, MESSAGE_ERROR, SiteMessage.TYPE_STOP );
311 
312                 return null;
313             }
314 
315             if ( ( directory.getRoleKey( ) != null ) && !directory.getRoleKey( ).equals( Directory.ROLE_NONE ) && SecurityService.isAuthenticationEnable( )
316                     && !SecurityService.getInstance( ).isUserInRole( request, directory.getRoleKey( ) ) )
317             {
318                 SiteMessageService.setMessage( request, MESSAGE_ACCESS_DENIED, SiteMessage.TYPE_STOP );
319             }
320 
321             if ( directory.isEnabled( ) )
322             {
323                 if ( request.getParameter( PARAMETER_VIEW_DIRECTORY_RECORD ) != null )
324                 {
325                     if ( ( record == null )
326                             || ( ( record.getRoleKey( ) != null ) && !record.getRoleKey( ).equals( Directory.ROLE_NONE )
327                                     && SecurityService.isAuthenticationEnable( ) && !SecurityService.getInstance( )
328                                     .isUserInRole( request, record.getRoleKey( ) ) ) )
329                     {
330                         SiteMessageService.setMessage( request, MESSAGE_ACCESS_DENIED, SiteMessage.TYPE_STOP );
331 
332                         return null;
333                     }
334 
335                     record.setDirectory( directory );
336 
337                     bSingleResult = true;
338 
339                     String strDirectoryRecord = getHtmlResultRecord( directory, record, request.getLocale( ), plugin, session );
340 
341                     List<Integer> lIdRecordList = new ArrayList<Integer>( );
342 
343                     lIdRecordList.add( record.getIdRecord( ) );
344 
345                     if ( lIdRecordList.size( ) > 0 )
346                     {
347                         List<RecordField> lRecordField = RecordFieldHome.getRecordFieldListByRecordIdList( lIdRecordList, plugin );
348                         model.put( MARK_RESULT_RECORD_FIELD_LIST, lRecordField );
349                     }
350                     model.put( MARK_STR_RESULT_RECORD, strDirectoryRecord );
351                 }
352                 else
353                 {
354                     searchFields.setCurrentPageIndex( Paginator.getPageIndex( request, Paginator.PARAMETER_PAGE_INDEX, searchFields.getCurrentPageIndex( ) ) );
355                     searchFields.setItemsPerPage( directory.getNumberRecordPerPage( ) );
356                     // Init Map query if requested
357                     initMapQuery( request, searchFields, directory );
358 
359                     if ( request.getParameter( PARAMETER_SEARCH ) != null )
360                     {
361                         // get search filter
362                         try
363                         {
364                             HashMap<String, List<RecordField>> mapQuery = DirectoryUtils.getSearchRecordData( request, directory.getIdDirectory( ), plugin,
365                                     request.getLocale( ) );
366 
367                             searchFields.setMapQuery( mapQuery );
368                             searchFields.setIdDirectory( directory.getIdDirectory( ) );
369                         }
370                         catch( DirectoryErrorException error )
371                         {
372                             if ( error.isMandatoryError( ) )
373                             {
374                                 Object [ ] tabRequiredFields = {
375                                     error.getTitleField( )
376                                 };
377                                 SiteMessageService.setMessage( request, MESSAGE_DIRECTORY_ERROR_MANDATORY_FIELD, tabRequiredFields, SiteMessage.TYPE_STOP );
378                             }
379                             else
380                             {
381                                 Object [ ] tabRequiredFields = {
382                                         error.getTitleField( ), error.getErrorMessage( )
383                                 };
384                                 SiteMessageService.setMessage( request, MESSAGE_DIRECTORY_ERROR, tabRequiredFields, SiteMessage.TYPE_STOP );
385                             }
386                         }
387                     }
388 
389                     if ( searchFields.getMapQuery( ) != null )
390                     {
391                         // call search service
392                         searchFields.setIsDisabled( RecordFieldFilter.FILTER_TRUE );
393 
394                         List<Integer> listResultRecordId = new ArrayList<Integer>( );
395 
396                         if ( SecurityService.isAuthenticationEnable( ) )
397                         {
398                             SecurityService securityService = SecurityService.getInstance( );
399                             LuteceUser user = securityService.getRegisteredUser( request );
400                             List<String> roleKeyList = new ArrayList<String>( );
401 
402                             if ( user != null )
403                             {
404                                 String [ ] lRoles = securityService.getRolesByUser( user );
405                                 if ( lRoles != null )
406                                 {
407                                     roleKeyList = new ArrayList<String>( Arrays.asList( lRoles ) );
408                                 }
409                             }
410 
411                             searchFields.setRoleKeyList( roleKeyList );
412                             searchFields.setIncludeRoleNone( true );
413                             searchFields.setIncludeRoleNull( true );
414                         }
415 
416                         // sort parameters
417                         searchFields.setSortParameters( request, directory, plugin );
418 
419                         listResultRecordId = DirectoryUtils.getListResults( request, directory, false, true, searchFields, null, request.getLocale( ) );
420 
421                         boolean bIsDisplayedDirectly = Boolean.parseBoolean( AppPropertiesService.getProperty( PROPERTY_DISPLAY_ONE_RESULT_DIRECTLY ) );
422 
423                         if ( bIsDisplayedDirectly && ( listResultRecordId.size( ) == 1 ) && ( session.getAttribute( SESSION_ONE_RECORD_ID ) == null ) )
424                         {
425                             record = recordService.findByPrimaryKey( listResultRecordId.get( 0 ), plugin );
426 
427                             if ( ( record != null ) && ( record.getDirectory( ) != null ) )
428                             {
429                                 directory = DirectoryHome.findByPrimaryKey( record.getDirectory( ).getIdDirectory( ), plugin );
430                             }
431 
432                             if ( ( record == null )
433                                     || ( ( record.getRoleKey( ) != null ) && !record.getRoleKey( ).equals( Directory.ROLE_NONE )
434                                             && SecurityService.isAuthenticationEnable( ) && !SecurityService.getInstance( ).isUserInRole( request,
435                                             record.getRoleKey( ) ) ) )
436                             {
437                                 SiteMessageService.setMessage( request, MESSAGE_ACCESS_DENIED, SiteMessage.TYPE_STOP );
438 
439                                 return null;
440                             }
441 
442                             record.setDirectory( directory );
443 
444                             String strDirectoryRecord = getHtmlResultRecord( directory, record, request.getLocale( ), plugin, session );
445                             model.put( MARK_STR_RESULT_RECORD, strDirectoryRecord );
446                             bSingleResult = true;
447                             model.put( MARK_ONE_RESULT, true );
448 
449                             session.setAttribute( SESSION_ONE_RECORD_ID, record.getIdRecord( ) );
450 
451                             listRecord = (List<Record>) session.getAttribute( SESSION_ID_LAST_RECORD );
452 
453                             if ( ( listRecord != null ) && ( listRecord.size( ) > 0 )
454                                     && ( listRecord.get( listRecord.size( ) - 1 ).getIdRecord( ) != record.getIdRecord( ) ) )
455                             {
456                                 listRecord.add( record );
457                             }
458                             else
459                                 if ( listRecord == null )
460                                 {
461                                     listRecord = new ArrayList<Record>( );
462                                     listRecord.add( record );
463                                 }
464 
465                             session.setAttribute( SESSION_ID_LAST_RECORD, listRecord );
466 
467                             listIdDirectory = (List<Integer>) session.getAttribute( SESSION_ID_LAST_DIRECTORY );
468 
469                             if ( ( listIdDirectory != null ) && ( listIdDirectory.size( ) > 0 )
470                                     && !listIdDirectory.get( listIdDirectory.size( ) - 1 ).equals( record.getDirectory( ).getIdDirectory( ) ) )
471                             {
472                                 listIdDirectory.add( record.getDirectory( ).getIdDirectory( ) );
473                             }
474                             else
475                                 if ( listIdDirectory == null )
476                                 {
477                                     listIdDirectory = new ArrayList<Integer>( );
478                                     listIdDirectory.add( record.getDirectory( ).getIdDirectory( ) );
479                                 }
480 
481                             session.setAttribute( SESSION_ID_LAST_DIRECTORY, listIdDirectory );
482                         }
483                         else
484                         {
485                             session.setAttribute( SESSION_ONE_RECORD_ID, null );
486                         }
487 
488                         if ( ( listResultRecordId.size( ) != 1 ) || !bIsDisplayedDirectly )
489                         {
490                             bSingleResult = false;
491 
492                             Paginator<Integer> paginator = new Paginator<Integer>( listResultRecordId, searchFields.getItemsPerPage( ),
493                                     urlDirectoryXpage.getUrl( ), Paginator.PARAMETER_PAGE_INDEX, searchFields.getCurrentPageIndex( ) );
494 
495                             model.put( MARK_PAGINATOR, paginator );
496 
497                             List<Record> lRecord = recordService.loadListByListId( paginator.getPageItems( ), plugin );
498 
499                             if ( lRecord.size( ) > 0 )
500                             {
501                                 String strResultList = getHtmlResultList( directory, lRecord, request.getLocale( ), plugin );
502 
503                                 List<Integer> lIdRecordList = new ArrayList<Integer>( );
504                                 for ( Record elementlRecord : lRecord )
505                                 {
506                                     lIdRecordList.add( elementlRecord.getIdRecord( ) );
507                                 }
508                                 if ( lIdRecordList.size( ) > 0 )
509                                 {
510                                     List<RecordField> lRecordField = RecordFieldHome.getRecordFieldListByRecordIdList( lIdRecordList, plugin );
511                                     model.put( MARK_RESULT_RECORD_FIELD_LIST, lRecordField );
512                                 }
513                                 // getRecordFieldListByRecordIdList( List<Integer> lIdRecordList, Plugin plugin )
514 
515                                 model.put( MARK_STR_RESULT_LIST, strResultList );
516                             }
517                         }
518                     }
519                     else
520                     {
521                         // if map_query is null, indicate that
522                         model.put( MARK_NEW_SEARCH, Integer.valueOf( 1 ) );
523                     }
524 
525                     String strFormSearch = getHtmlFormSearch( directory, searchFields.getMapQuery( ), request, plugin );
526                     model.put( MARK_STR_FORM_SEARCH, strFormSearch );
527                 }
528 
529                 model.put( MARK_LOCALE, request.getLocale( ) );
530             }
531             else
532             {
533                 model.put( MARK_UNAVAILABILITY_MESSAGE, directory.getUnavailabilityMessage( ) );
534             }
535 
536             EntryFilter filterGeolocation = new EntryFilter( );
537             filterGeolocation.setIdDirectory( directory.getIdDirectory( ) );
538             filterGeolocation.setIdType( AppPropertiesService.getPropertyInt( PROPERTY_ENTRY_TYPE_GEOLOCATION, 16 ) );
539 
540             if ( bSingleResult != null )
541             {
542                 if ( bSingleResult )
543                 {
544                     filterGeolocation.setIsShownInResultRecord( 1 );
545                 }
546                 else
547                 {
548                     filterGeolocation.setIsShownInResultList( 1 );
549                 }
550             }
551 
552             List<IEntry> entriesGeolocationList = EntryHome.getEntryList( filterGeolocation, plugin );
553             model.put( MARK_ENTRY_LIST_GEOLOCATION, entriesGeolocationList );
554             model.put( MARK_WEBAPP_URL, AppPathService.getBaseUrl( request ) );
555 
556             HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_XPAGE_FRAME_DIRECTORY, request.getLocale( ), model );
557             page.setContent( template.getHtml( ) );
558             session.setAttribute( SESSION_DIRECTORY_SITE_SEARCH_FIELDS, searchFields );
559         }
560 
561         return page;
562     }
563 
564     /**
565      * return the HTML form search
566      *
567      * @param directory
568      *            the directory
569      * @param mapQuery
570      *            the mapQuerySearch
571      * @param request
572      *            the HttpServletRequesr
573      * @param plugin
574      *            the plugin
575      * @return the html form search
576      */
577     private String getHtmlFormSearch( Directory directory, HashMap<String, List<RecordField>> mapQuery, HttpServletRequest request, Plugin plugin )
578     {
579         // build entryFilter
580         EntryFilter entryFilter = new EntryFilter( );
581         entryFilter.setIdDirectory( directory.getIdDirectory( ) );
582         entryFilter.setIsGroup( EntryFilter.FILTER_FALSE );
583         entryFilter.setIsComment( EntryFilter.FILTER_FALSE );
584         entryFilter.setIsIndexed( EntryFilter.FILTER_TRUE );
585 
586         List<IEntry> listEntryFormMainSearch = new ArrayList<IEntry>( );
587         List<IEntry> listEntryFormComplementarySearch = new ArrayList<IEntry>( );
588         IEntry entryStore;
589 
590         for ( IEntry entry : EntryHome.getEntryList( entryFilter, plugin ) )
591         {
592             entryStore = EntryHome.findByPrimaryKey( entry.getIdEntry( ), plugin );
593 
594             if ( entryStore.isRoleAssociated( ) )
595             {
596                 entryStore.setFields( DirectoryUtils.getAuthorizedFieldsByRole( request, entryStore.getFields( ) ) );
597             }
598 
599             if ( !entryStore.isShownInAdvancedSearch( ) )
600             {
601                 listEntryFormMainSearch.add( entryStore );
602             }
603             else
604             {
605                 listEntryFormComplementarySearch.add( entryStore );
606             }
607         }
608 
609         Map<String, Object> model = new HashMap<String, Object>( );
610         model.put( MARK_ENTRY_LIST_FORM_MAIN_SEARCH, listEntryFormMainSearch );
611         model.put( MARK_ENTRY_LIST_FORM_COMPLEMENTARY_SEARCH, listEntryFormComplementarySearch );
612         model.put( MARK_MAP_ID_ENTRY_LIST_RECORD_FIELD, mapQuery );
613         model.put( MARK_DIRECTORY, directory );
614         model.put( MARK_LOCALE, request.getLocale( ) );
615 
616         HttpSession session = request.getSession( );
617 
618         if ( session.getAttribute( SESSION_ONE_RECORD_ID ) != null )
619         {
620             model.put( MARK_ONE_SESSION_ID, session.getAttribute( SESSION_ONE_RECORD_ID ) );
621         }
622 
623         HtmlTemplate templateXmlFormSearch = AppTemplateService.getTemplate( TEMPLATE_XML_FORM_SEARCH, request.getLocale( ), model );
624 
625         File fileTemplate = null;
626         DirectoryXsl directoryXsl = DirectoryXslHome.findByPrimaryKey( directory.getIdFormSearchTemplate( ), plugin );
627 
628         if ( directoryXsl.getFile( ) != null )
629         {
630             fileTemplate = FileHome.findByPrimaryKey( directoryXsl.getFile( ).getIdFile( ), plugin );
631         }
632 
633         if ( ( fileTemplate != null ) && ( fileTemplate.getPhysicalFile( ) != null ) )
634         {
635             fileTemplate.setPhysicalFile( PhysicalFileHome.findByPrimaryKey( fileTemplate.getPhysicalFile( ).getIdPhysicalFile( ), plugin ) );
636 
637             XmlTransformerService xmlTransformerService = new XmlTransformerService( );
638             PhysicalFile physicalFile = fileTemplate.getPhysicalFile( );
639             String strXslId = XSL_UNIQUE_PREFIX_ID + physicalFile.getIdPhysicalFile( );
640             String strResult = xmlTransformerService.transformBySourceWithXslCache( templateXmlFormSearch.getHtml( ), physicalFile.getValue( ), strXslId, null,
641                     null );
642 
643             return strResult;
644         }
645 
646         return DirectoryUtils.EMPTY_STRING;
647     }
648 
649     /**
650      * return the HTML result list
651      *
652      * @param directory
653      *            the directory
654      * @param listRecord
655      *            the list of record
656      * @param listEntry
657      *            the list of entry
658      * @param locale
659      *            the locale
660      * @param plugin
661      *            the plugin
662      * @return the HTML result list
663      */
664     private String getHtmlResultList( Directory directory, List<Record> listRecord, Locale locale, Plugin plugin )
665     {
666         StringBuffer strBufferListRecordXml = new StringBuffer( );
667         StringBuffer strBufferListEntryXml = new StringBuffer( );
668 
669         // get directory Entry
670         EntryFilter entryFilter = new EntryFilter( );
671         entryFilter.setIdDirectory( directory.getIdDirectory( ) );
672         entryFilter.setIsGroup( EntryFilter.FILTER_FALSE );
673         entryFilter.setIsComment( EntryFilter.FILTER_FALSE );
674         entryFilter.setIsShownInResultList( EntryFilter.FILTER_TRUE );
675 
676         List<IEntry> listEntrySearchResult = EntryHome.getEntryList( entryFilter, plugin );
677 
678         Map<Integer, Field> hashFields = DirectoryUtils.getMapFieldsOfListEntry( listEntrySearchResult, plugin );
679 
680         for ( Record record : listRecord )
681         {
682 
683             State state = null;
684 
685             if ( directory.getIdWorkflow( ) != DirectoryUtils.CONSTANT_ID_NULL && WorkflowService.getInstance( ).isAvailable( ) )
686             {
687                 state = WorkflowService.getInstance( ).getState( record.getIdRecord( ), Record.WORKFLOW_RESOURCE_TYPE, directory.getIdWorkflow( ),
688                         Integer.valueOf( directory.getIdDirectory( ) ) );
689             }
690 
691             strBufferListRecordXml.append( record.getXml( plugin, locale, false, state, listEntrySearchResult, true, true, false, true, hashFields ) );
692         }
693 
694         for ( IEntry entry : listEntrySearchResult )
695         {
696             entry.getXml( plugin, locale, strBufferListEntryXml );
697         }
698 
699         HashMap<String, String> model = new HashMap<String, String>( );
700 
701         if ( ( directory.getIdWorkflow( ) != DirectoryUtils.CONSTANT_ID_NULL ) && WorkflowService.getInstance( ).isAvailable( ) )
702         {
703             model.put( TAG_DISPLAY, TAG_YES );
704         }
705         else
706         {
707             model.put( TAG_DISPLAY, TAG_NO );
708         }
709 
710         XmlUtil.addEmptyElement( strBufferListEntryXml, TAG_STATUS, model );
711 
712         StringBuilder strBufferXml = new StringBuilder( );
713         strBufferXml.append( XmlUtil.getXmlHeader( ) );
714         strBufferXml.append( directory.getXml( plugin, locale, strBufferListRecordXml, strBufferListEntryXml ) );
715 
716         File fileTemplate = null;
717         DirectoryXsl directoryXsl = DirectoryXslHome.findByPrimaryKey( directory.getIdResultListTemplate( ), plugin );
718 
719         if ( directoryXsl.getFile( ) != null )
720         {
721             fileTemplate = FileHome.findByPrimaryKey( directoryXsl.getFile( ).getIdFile( ), plugin );
722         }
723 
724         if ( ( fileTemplate != null ) && ( fileTemplate.getPhysicalFile( ) != null ) )
725         {
726             fileTemplate.setPhysicalFile( PhysicalFileHome.findByPrimaryKey( fileTemplate.getPhysicalFile( ).getIdPhysicalFile( ), plugin ) );
727 
728             HashMap<String, String> params = new HashMap<String, String>( );
729             String strParamTitleDescriptive = I18nService.getLocalizedString( PROPERTY_DIRECTORY_FRAME_TITLE_DESCRIPTIVE, locale );
730             String strParamTitleSortAsc = I18nService.getLocalizedString( PROPERTY_DIRECTORY_RESULT_TITLE_SORT_ASC, locale );
731             String strParamTitleSortDesc = I18nService.getLocalizedString( PROPERTY_DIRECTORY_RESULT_TITLE_SORT_DESC, locale );
732 
733             params.put( MARK_TITLE_SORT_ASC, strParamTitleSortAsc );
734             params.put( MARK_TITLE_SORT_DESC, strParamTitleSortDesc );
735             params.put( MARK_TITLE_DESCRIPTIVE, strParamTitleDescriptive );
736 
737             XmlTransformerService xmlTransformerService = new XmlTransformerService( );
738             PhysicalFile physicalFile = fileTemplate.getPhysicalFile( );
739             String strXslId = XSL_UNIQUE_PREFIX_ID + physicalFile.getIdPhysicalFile( );
740             String strResult = xmlTransformerService.transformBySourceWithXslCache( strBufferXml.toString( ), physicalFile.getValue( ), strXslId, params, null );
741 
742             return strResult;
743         }
744 
745         return DirectoryUtils.EMPTY_STRING;
746     }
747 
748     /**
749      * return the HTML result lrcord
750      *
751      * @param directory
752      *            the directory
753      * @param record
754      *            the record
755      * @param locale
756      *            the locale
757      * @param plugin
758      *            the plugin
759      * @param session
760      *            The session
761      * @return the Html result record
762      */
763     private String getHtmlResultRecord( Directory directory, Record record, Locale locale, Plugin plugin, HttpSession session )
764     {
765         RecordFieldFilter filter = new RecordFieldFilter( );
766         filter.setIdRecord( record.getIdRecord( ) );
767         filter.setIsEntryShownInResultRecord( RecordFieldFilter.FILTER_TRUE );
768 
769         List<RecordField> listRecordField = RecordFieldHome.getRecordFieldList( filter, plugin );
770         record.setListRecordField( listRecordField );
771 
772         StringBuffer strBufferListEntryXml = new StringBuffer( );
773 
774         // get directory Entry
775         EntryFilter entryFilter = new EntryFilter( );
776         entryFilter.setIdDirectory( record.getDirectory( ).getIdDirectory( ) );
777 
778         List<IEntry> listEntry = DirectoryUtils.getFormEntriesByFilter( entryFilter, plugin );
779 
780         for ( IEntry entry : listEntry )
781         {
782             entry.getXml( plugin, locale, strBufferListEntryXml );
783         }
784 
785         StringBuffer strBufferListRecordXml = new StringBuffer( );
786         strBufferListRecordXml.append( record.getXml( plugin, locale, false, null, listEntry, true, true, false, true,
787                 DirectoryUtils.getMapFieldsOfListEntry( listEntry, plugin ) ) );
788 
789         StringBuilder strBufferXml = new StringBuilder( );
790         strBufferXml.append( XmlUtil.getXmlHeader( ) );
791         strBufferXml.append( directory.getXml( plugin, locale, strBufferListRecordXml, strBufferListEntryXml ) );
792 
793         File fileTemplate = null;
794         DirectoryXsl directoryXsl = DirectoryXslHome.findByPrimaryKey( record.getDirectory( ).getIdResultRecordTemplate( ), plugin );
795 
796         if ( directoryXsl.getFile( ) != null )
797         {
798             fileTemplate = FileHome.findByPrimaryKey( directoryXsl.getFile( ).getIdFile( ), plugin );
799         }
800 
801         if ( ( fileTemplate != null ) && ( fileTemplate.getPhysicalFile( ) != null ) )
802         {
803             fileTemplate.setPhysicalFile( PhysicalFileHome.findByPrimaryKey( fileTemplate.getPhysicalFile( ).getIdPhysicalFile( ), plugin ) );
804 
805             HashMap<String, String> params = new HashMap<String, String>( );
806             String strParamTitleBackSearch = I18nService.getLocalizedString( PROPERTY_DIRECTORY_FRAME_TITLE_BACK_SEARCH, locale );
807             String strParamLabelBackSearch = I18nService.getLocalizedString( PROPERTY_DIRECTORY_FRAME_LABEL_BACK_SEARCH, locale );
808 
809             params.put( MARK_TITLE_BACK_SEARCH, strParamTitleBackSearch );
810             params.put( MARK_LABEL_BACK_SEARCH, strParamLabelBackSearch );
811             params.put( MARK_ID_DIRECTORY, Integer.toString( record.getDirectory( ).getIdDirectory( ) ) );
812 
813             // Params linked with last record
814             if ( session.getAttribute( SESSION_ID_LAST_RECORD ) != null )
815             {
816                 List<Record> listRecord = (List<Record>) session.getAttribute( SESSION_ID_LAST_RECORD );
817                 String strParamTitleBackRecord = I18nService.getLocalizedString( PROPERTY_DIRECTORY_FRAME_TITLE_BACK_RECORD, locale );
818                 String strParamLabelBackRecord = I18nService.getLocalizedString( PROPERTY_DIRECTORY_FRAME_LABEL_BACK_RECORD, locale );
819                 params.put( MARK_TITLE_BACK_RECORD, strParamTitleBackRecord );
820                 params.put( MARK_LABEL_BACK_RECORD, strParamLabelBackRecord );
821                 params.put( MARK_IS_EXTEND_INSTALLED, Boolean.toString( PortalService.isExtendActivated( ) ) );
822 
823                 if ( ( listRecord != null ) && ( listRecord.size( ) > 1 ) )
824                 {
825                     Record lastRecord = listRecord.get( listRecord.size( ) - 2 );
826                     params.put( MARK_ID_LAST_RECORD, "" + lastRecord.getIdRecord( ) );
827                 }
828             }
829 
830             if ( session.getAttribute( SESSION_ID_LAST_DIRECTORY ) != null )
831             {
832                 List<Integer> listIdDirectory = (List<Integer>) session.getAttribute( SESSION_ID_LAST_DIRECTORY );
833 
834                 if ( ( listIdDirectory != null ) && ( listIdDirectory.size( ) > 1 ) )
835                 {
836                     Integer lastIdDirectory = listIdDirectory.get( listIdDirectory.size( ) - 2 );
837                     params.put( MARK_ID_LAST_DIRECTORY, "" + lastIdDirectory );
838                 }
839             }
840 
841             XmlTransformerService xmlTransformerService = new XmlTransformerService( );
842             PhysicalFile physicalFile = fileTemplate.getPhysicalFile( );
843             String strXslId = XSL_UNIQUE_PREFIX_ID + physicalFile.getIdPhysicalFile( );
844             String strResult = xmlTransformerService.transformBySourceWithXslCache( strBufferXml.toString( ), physicalFile.getValue( ), strXslId, params, null );
845 
846             return strResult;
847         }
848 
849         return DirectoryUtils.EMPTY_STRING;
850     }
851 
852     /**
853      * Returns the html code of the search page
854      *
855      * @param request
856      *            the http request
857      * @param plugin
858      *            the plugin
859      * @return the html page
860      * @throws SiteMessageException
861      *             a exception that triggers a site message
862      */
863     public String getSearchPage( HttpServletRequest request, Plugin plugin ) throws SiteMessageException
864     {
865         String strQuery = request.getParameter( PARAMETER_QUERY );
866 
867         HashMap<String, Object> model = new HashMap<String, Object>( );
868 
869         if ( StringUtils.isNotBlank( strQuery ) )
870         {
871             Date dateBegin = null;
872             Date dateEnd = null;
873 
874             String strOperator = request.getParameter( PARAMETER_OPERATOR );
875             String strDateBegin = request.getParameter( PARAMETER_DATE_BEGIN );
876             String strDateEnd = request.getParameter( PARAMETER_DATE_END );
877 
878             // Mandatory fields
879             if ( StringUtils.isBlank( strOperator ) )
880             {
881                 Object [ ] tabRequiredFields = {
882                     PARAMETER_OPERATOR
883                 };
884                 SiteMessageService.setMessage( request, MESSAGE_DIRECTORY_ERROR_MANDATORY_FIELD, tabRequiredFields, SiteMessage.TYPE_STOP );
885             }
886 
887             // Safety checks
888             if ( StringUtils.isNotBlank( strDateBegin ) )
889             {
890                 dateBegin = DateUtil.formatDate( strDateBegin, request.getLocale( ) );
891 
892                 if ( dateBegin == null )
893                 {
894                     SiteMessageService.setMessage( request, MESSAGE_SEARCH_DATE_VALIDITY, SiteMessage.TYPE_STOP );
895                 }
896             }
897 
898             if ( StringUtils.isNotBlank( strDateEnd ) )
899             {
900                 dateEnd = DateUtil.formatDate( strDateEnd, request.getLocale( ) );
901 
902                 if ( dateEnd == null )
903                 {
904                     SiteMessageService.setMessage( request, MESSAGE_SEARCH_DATE_VALIDITY, SiteMessage.TYPE_STOP );
905                 }
906             }
907 
908             if ( !strOperator.equalsIgnoreCase( OPERATOR_AND ) && !strOperator.equalsIgnoreCase( OPERATOR_OR ) )
909             {
910                 SiteMessageService.setMessage( request, MESSAGE_SEARCH_OPERATOR_VALIDITY, SiteMessage.TYPE_STOP );
911             }
912 
913             // Check XSS characters
914             if ( SecurityUtil.containsXssCharacters( request, strQuery ) )
915             {
916                 SiteMessageService.setMessage( request, MESSAGE_INVALID_SEARCH_TERMS, SiteMessage.TYPE_STOP );
917             }
918 
919             // Use LuceneSearchEngine
920             SearchEngine engine = (SearchEngine) SpringContextService.getBean( BEAN_SEARCH_ENGINE );
921             List<SearchResult> listResults = engine.getSearchResults( strQuery, request );
922 
923             model.put( MARK_RESULT_LIST, listResults );
924 
925             // re-populate search parameters
926             model.put( MARK_QUERY, strQuery );
927             model.put( MARK_OPERATOR, strOperator );
928             model.put( MARK_DATE_BEGIN, strDateBegin );
929             model.put( MARK_DATE_END, strDateEnd );
930         }
931 
932         // Display the list of all Directory
933         DirectoryFilter filter = new DirectoryFilter( );
934         filter.setIsDisabled( DirectoryFilter.FILTER_TRUE );
935 
936         List<Directory> listDirectory = DirectoryHome.getDirectoryList( filter, plugin );
937         List<Directory> listDirectoryAuthorized;
938 
939         if ( SecurityService.isAuthenticationEnable( ) )
940         {
941             listDirectoryAuthorized = new ArrayList<Directory>( );
942 
943             for ( Directory directory : listDirectory )
944             {
945                 if ( ( directory.getRoleKey( ) == null ) || directory.getRoleKey( ).equals( Directory.ROLE_NONE )
946                         || SecurityService.getInstance( ).isUserInRole( request, directory.getRoleKey( ) ) )
947                 {
948                     listDirectoryAuthorized.add( directory );
949                 }
950             }
951         }
952         else
953         {
954             listDirectoryAuthorized = listDirectory;
955         }
956 
957         model.put( MARK_DIRECTORY_LIST, listDirectoryAuthorized );
958 
959         model.put( MARK_LOCALE, request.getLocale( ) );
960 
961         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_XPAGE_VIEW_ALL_DIRECTORIES, request.getLocale( ), model );
962 
963         return template.getHtml( );
964     }
965 
966     /**
967      * re init the map query used for searching
968      * 
969      * @param request
970      *            the HttpServletRequest
971      * @param searchFields
972      *            the searchFields
973      * @param directory
974      *            the directory
975      */
976     private static void initMapQuery( HttpServletRequest request, DirectorySiteSearchFields searchFields, Directory directory )
977     {
978         if ( ( request.getParameter( INIT_MAP_QUERY ) != null )
979                 || ( ( request.getParameter( PARAMETER_SEARCH ) == null ) && ( searchFields.getIdDirectory( ) != directory.getIdDirectory( ) ) ) )
980         {
981             searchFields.setMapQuery( null );
982         }
983     }
984 
985     /**
986      * return a init searchField
987      * 
988      * @param directory
989      *            the directory
990      * @return the DirectorySiteSearchFields
991      */
992     private DirectorySiteSearchFields getInitDirectorySearchField( )
993     {
994         DirectorySiteSearchFields searchFields = new DirectorySiteSearchFields( );
995 
996         return searchFields;
997     }
998 }