View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of 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.appointment.modules.solrsearchapp.service;
35  
36  import java.time.LocalDateTime;
37  import java.time.format.DateTimeParseException;
38  import java.util.AbstractMap.SimpleImmutableEntry;
39  import java.util.Arrays;
40  import java.util.Collections;
41  import java.util.List;
42  import java.util.Map;
43  
44  import javax.servlet.http.HttpServletRequest;
45  
46  import org.apache.commons.lang3.StringUtils;
47  import org.apache.commons.lang3.ArrayUtils;
48  import org.apache.solr.client.solrj.SolrQuery;
49  import org.apache.solr.client.solrj.util.ClientUtils;
50  
51  public class SolrQueryService
52  {
53      private static final String SOLR_FIELD_SITE = "site";
54      private static final String SOLR_FIELD_CATEGORY = "categorie";
55      public static final String SOLR_FIELD_FORM_UID_TITLE = "form_id_title_string";
56      private static final String SOLR_FIELD_FORM_UID = "uid_form_string";
57      private static final String SOLR_QUERY_ALL = "*:*";
58      private static final String SOLR_FILTERQUERY_ALLOWED_NOW = "{!frange l=0}sub(sub(ms(date),mul(3600000,min_hours_before_appointment_long)),ms())";
59      private static final String SOLR_FILTERQUERY_DAY_OPEN = "day_open_string:true";
60      private static final String SOLR_FILTERQUERY_ENABLED = "enabled_string:true";
61      private static final String SOLR_FILTERQUERY_ACTIVE = "appointment_active_string:true";
62      private static final String SOLR_FIELD_TYPE = "type";
63      public static final String SOLR_FIELD_DATE = "date";
64      private static final String SOLR_FIELD_MINUTE_OF_DAY = "minute_of_day_long";
65      private static final String SOLR_NB_CONSECUTIVES_SLOTS = "nb_consecutives_slots_long";
66      private static final String SOLR_MAX_CONSECUTIVES_SLOTS = "max_consecutives_slots_long";
67      private static final String SOLR_ROLE = "role";
68      public static final String SOLR_FIELD_DAY_OF_WEEK = "day_of_week_long";
69      private static final String SOLR_TYPE_APPOINTMENT_SLOT = "appointment-slot";
70      public static final String VALUE_FQ_EMPTY = "__EMPTY__";
71  
72      public static final List<SimpleImmutableEntry<String, String>> EXACT_FACET_QUERIES = Collections
73              .unmodifiableList( Arrays.asList( new SimpleImmutableEntry<>( SOLR_FIELD_SITE, Utilities.PARAMETER_SITE ),
74                      new SimpleImmutableEntry<>( SOLR_FIELD_CATEGORY, Utilities.PARAMETER_CATEGORY ),
75                      new SimpleImmutableEntry<>( SOLR_FIELD_FORM_UID, Utilities.PARAMETER_FORM ) ) );
76  
77      public static final List<SimpleImmutableEntry<String, String>> FACET_FIELDS = Collections
78              .unmodifiableList( Arrays.asList( new SimpleImmutableEntry<>( SOLR_FIELD_SITE, Utilities.MARK_ITEM_SITES ),
79                      new SimpleImmutableEntry<>( SOLR_FIELD_CATEGORY, Utilities.MARK_ITEM_CATEGORIES ),
80                      new SimpleImmutableEntry<>( SOLR_FIELD_FORM_UID_TITLE, Utilities.MARK_ITEM_FORMS ) ) );
81  
82      private SolrQueryService( )
83      {
84          // private constructor
85      }
86  
87      public static SolrQuery getCommonFilteredQuery( HttpServletRequest request, Map<String, String> searchParameters,
88              Map<String, String [ ]> searchMultiParameters )
89      {
90          SolrQuery query = new SolrQuery( );
91          query.setQuery( SOLR_QUERY_ALL );
92          query.addFilterQuery( SOLR_FIELD_TYPE + ":" + SOLR_TYPE_APPOINTMENT_SLOT );
93          query.addFilterQuery( SOLR_FILTERQUERY_ALLOWED_NOW );
94          query.addFilterQuery( SOLR_FILTERQUERY_DAY_OPEN );
95          query.addFilterQuery( SOLR_FILTERQUERY_ENABLED );
96          query.addFilterQuery( SOLR_FILTERQUERY_ACTIVE );
97  
98          for ( SimpleImmutableEntry<String, String> entry : EXACT_FACET_QUERIES )
99          {
100             addFacetToQuery( query, request, searchParameters, entry );
101         }
102 
103         StringBuilder sbFqDaysOfWeek = new StringBuilder( );
104         String [ ] searchDays = Utilities.getSearchMultiParameter( Utilities.PARAMETER_DAYS_OF_WEEK, request, searchMultiParameters );
105         if ( ArrayUtils.isNotEmpty( searchDays ) )
106         {
107             sbFqDaysOfWeek.append( "{!tag=tag" + SOLR_FIELD_DAY_OF_WEEK + "}" + SOLR_FIELD_DAY_OF_WEEK + ":(" );
108             for ( int nDay = 0; nDay < searchDays.length; nDay++ )
109             {
110                 if ( nDay > 0 )
111                 {
112                     sbFqDaysOfWeek.append( " OR " );
113                 }
114                 sbFqDaysOfWeek.append( searchDays [nDay] );
115             }
116             sbFqDaysOfWeek.append( ")" );
117         }
118         query.addFilterQuery( sbFqDaysOfWeek.toString( ) );
119         query.addFacetField( "{!ex=tag" + SOLR_FIELD_DAY_OF_WEEK + "}" + SOLR_FIELD_DAY_OF_WEEK );
120 
121         String strFromDate = Utilities.getSearchParameterValue( Utilities.PARAMETER_FROM_DATE, request, searchParameters );
122         String strFromTime = Utilities.getSearchParameterValue( Utilities.PARAMETER_FROM_TIME, request, searchParameters );
123         String strToDate = Utilities.getSearchParameterValue( Utilities.PARAMETER_TO_DATE, request, searchParameters );
124         String strToTime = Utilities.getSearchParameterValue( Utilities.PARAMETER_TO_TIME, request, searchParameters );
125         LocalDateTime localDateTimeFrom = null;
126         try
127         {
128             localDateTimeFrom = LocalDateTime.parse( strFromDate + " " + strFromTime, Utilities.inputFormatter );
129         }
130         catch( DateTimeParseException e )
131         {
132             localDateTimeFrom = null;
133         }
134         String strSolrDateTimeFrom = "*";
135         if ( localDateTimeFrom != null )
136         {
137             strSolrDateTimeFrom = localDateTimeFrom.format( Utilities.outputFormatter );
138         }
139         LocalDateTime localDateTimeTo = null;
140         try
141         {
142             localDateTimeTo = LocalDateTime.parse( strToDate + " " + strToTime, Utilities.inputFormatter );
143         }
144         catch( DateTimeParseException e )
145         {
146             localDateTimeTo = null;
147         }
148         String strSolrDateTimeTo = "*";
149         if ( localDateTimeTo != null )
150         {
151             strSolrDateTimeTo = localDateTimeTo.format( Utilities.outputFormatter );
152         }
153         query.addFilterQuery( SOLR_FIELD_DATE + ":[" + strSolrDateTimeFrom + " TO " + strSolrDateTimeTo + "]" );
154         String strFromDayMinute = Utilities.getSearchParameterValue( Utilities.PARAMETER_FROM_DAY_MINUTE, request, searchParameters );
155         String strToDayMinute = Utilities.getSearchParameterValue( Utilities.PARAMETER_TO_DAY_MINUTE, request, searchParameters );
156         String strSolrDayMinuteFrom = "*";
157         if ( strFromDayMinute != null )
158         {
159             strSolrDayMinuteFrom = strFromDayMinute;
160         }
161         String strSolrDayMinuteTo = "*";
162         if ( strToDayMinute != null )
163         {
164             strSolrDayMinuteTo = strToDayMinute;
165         }
166         query.addFilterQuery( SOLR_FIELD_MINUTE_OF_DAY + ":[" + strSolrDayMinuteFrom + " TO " + strSolrDayMinuteTo + "]" );
167 
168         String strNbConsecutiveSlots = Utilities.getSearchParameterValue( Utilities.PARAMETER_NB_SLOTS, request, searchParameters );
169         int nbConsecutiveSlots = Integer.parseInt( strNbConsecutiveSlots );
170         query.addFilterQuery( SOLR_NB_CONSECUTIVES_SLOTS + ":[" + nbConsecutiveSlots + " TO *]" );
171         query.addFilterQuery( SOLR_MAX_CONSECUTIVES_SLOTS + ":[" + nbConsecutiveSlots + " TO *]" );
172 
173         String strRole = Utilities.getSearchParameterValue( Utilities.PARAMETER_ROLE, request, searchParameters );
174         if ( StringUtils.isNotEmpty( strRole ) && !"none".equals( strRole ) )
175         {
176             query.addFilterQuery( SOLR_ROLE + ":" + strRole );
177         }
178         return query;
179     }
180 
181     private static void addFacetToQuery( SolrQuery query, HttpServletRequest request, Map<String, String> searchParameters,
182             SimpleImmutableEntry<String, String> entry )
183     {
184         String strValue = Utilities.getSearchParameterValue( entry.getValue( ), request, searchParameters );
185         String strFacetField;
186         if ( SOLR_FIELD_FORM_UID.equals( entry.getKey( ) ) )
187         {
188             strFacetField = SOLR_FIELD_FORM_UID_TITLE;
189         }
190         else
191         {
192             strFacetField = entry.getKey( );
193         }
194         if ( StringUtils.isNotBlank( strValue ) )
195         {
196             String strFilterQuery;
197             if ( VALUE_FQ_EMPTY.equals( strValue ) )
198             {
199                 strFilterQuery = entry.getKey( ) + ":" + "\"\" OR (*:* NOT " + entry.getKey( ) + ":*)";
200             }
201             else
202             {
203                 strFilterQuery = entry.getKey( ) + ":" + ClientUtils.escapeQueryChars( strValue );
204             }
205             query.addFilterQuery( "{!tag=tag" + strFacetField + "}" + strFilterQuery );
206             strFacetField = "{!ex=tag" + strFacetField + "}" + strFacetField;
207         }
208         query.addFacetField( strFacetField );
209     }
210 }